NodeJS简易博客系统(四)Mongoose入门学习
一、模式(schemas)
1、定义schema
Mongoose的一切都始于一个Schema。每个schema映射到MongoDB的集合
(collection)和定义该集合(collection)中的文档的形式。
var mongoose = require('mongoose'); var Schema = mongoose.Schema; var blogSchema = new Schema({ title: String, author: String, body: String, comments: [{ body: String, date: Date }], date: { type: Date, default: Date.now }, hidden: Boolean, meta: { votes: Number, favs: Number } }); |
如果想后续添加额外的键(keys) ,使用Schema#add方法。在blogSchema每个key在我们的文件将被转换为相关SchemaType定义一个属性。允许使用的SchemaTypes:
- String
- Number
- Date
- Buffer
- Boolean
- Mixed
- ObjectId
- Array
用default来设置默认值。
2、模型创建
使用刚刚的schema定义,我们需要将我们的blogschema转成我们可以用的模型。
为此,我们通过 mongoose.model(modelName, schema) :
var Blog = mongoose.model('Blog', blogSchema); |
3、自定义文档实例方法
// define a schema var animalSchema = new Schema({ name: String, type: String }); // assign a function to the "methods" object of our animalSchema animalSchema.methods.findSimilarTypes = function(cb) { return this.model('Animal').find({ type: this.type }, cb); }; |
调用:
var Animal = mongoose.model('Animal', animalSchema); var dog = new Animal({ type: 'dog' }); dog.findSimilarTypes(function(err, dogs) { console.log(dogs); // woof }); |
4、自定义文档静态实例方法
// assign a function to the "statics" object of our animalSchema animalSchema.statics.findByName = function(name, cb) { return this.find({ name: new RegExp(name, 'i') }, cb); }; var Animal = mongoose.model('Animal', animalSchema); Animal.findByName('fido', function(err, animals) { console.log(animals); }); |
二、模型(models)
Models 是从 Schema
编译来的构造函数。 它们的实例就代表着可以从数据库保存和读取的 documents。 从数据库创建和读取 document 的所有操作都是通过 model 进行的。
1、简单实例
schema文件
var mongoose = require("mongoose"); module.exports = new mongoose.Schema({ username: String, password: String, isadmin:{ type:Boolean, default:false } }); |
model文件
var mongoose = require("mongoose"); var userschama = require("../schemas/users"); module.exports = mongoose.model("User",userschama); |
2、CRUD操作
1、Create
model对象.save() |
2、Retrieve
用 mongoose 查询文档相当容易啦,它支持 MongoDB 的高级( rich )查询语法。 查询文档可以用 model 的 find, findById, findOne, 和 where 这些静态方法。查询对象的size为small并且创建时间为近一年的数据:
model对象.find({ size: 'small' }).where('createdDate').gt(oneYearAgo).exec(callback);。 |
3、Update
model 的 update 方法可以修改数据库中的文档,不过不会把文档返回给应用层。如果想更新单独一条文档并且返回给应用层,可以使用 findOneAndUpdate 方法。
4、Delete
model
的 remove
方法可以删除所有匹配查询条件( conditions
)的文档。
Tank.remove({ size: 'large' }, function (err) { if (err) return handleError(err); // todo after removing }); |
三、文档(documents)
1、更新
Document 更新的方法同样有很多,我们先看看一个传统的实现,使用 findById:
Object.findById(id, function (err, object) { object.size = 'large'; |
这个方法先检索数据,接着更新(使用了 save)。 如果仅仅需要更新而不需要获取该数据, Model#update 就很适合:
Object.update({ _id: id }, { $set: { size: 'large' }}, callback); |
如果我们确实需要返回文档,这个方法更适合:
Object.findByIdAndUpdate(id, { $set: { size: 'large' }}, { new: true }, function (err, object) { if (err) return handleError(err); res.send(object); }); |
findAndUpdate/Remove 系列静态方法查找并返回最多1个文档。
注意:findAndUpdate/Remove 不会修改数据库时执行任何钩子或验证。 可以使用 runValidators 选项 获取一个验证的限制子集(待修改)。 但是你需要钩子和全文档验证,还是先 query 后 save 吧。
2、覆盖
可以用 .set() 覆盖整个文档。如果你要修改 在中间件中被保存的文档,这样就很方便。
Object.findById(id, function (err, object) { if (err) return handleError(err); // Now `otherObject` is a copy of `object` otherObject.set(object); }); |
3、子文档(Subdocument)
子文档是指嵌套在另一个文档中的文档。 在 Mongoose 中,这意味着你可以在里嵌套另一个 schema。 Mongoose 子文档有两种不同的概念:子文档数组和单个嵌套子文档。
var childSchema = new Schema({ name: 'string' }); var parentSchema = new Schema({ |
子文档与普通 document 类似。嵌套schema可以有自己的中间件、自定义检验逻辑、 虚拟值以及其他顶层schemas可用的特性。两者主要的不同点是子文档不能单独保存,他们会在他们的顶级文档保存时保存。
var Parent = mongoose.model('Parent', parentSchema); // `parent.children[0].save()` 无操作,虽然他触发了中间件 |
子文档跟普通 document一样有save和validate中间件。调用父文档的save()会触发其所有子文档的save()中间件,validate()中间件同理。
childSchema.pre('save', function (next) { var parent = new Parent({ children: [{ name: 'invalid' }] }); |
子文档的 pre('save') 和 pre('validate') 中间件执行于 顶层document的pre('save') 之前,顶层 document的pre('validate')之后。 因为save()前的验证就是一个内置中间件。
// 一下代码顺序打出 1-4 childSchema.pre('validate', function(next) { childSchema.pre('save', function(next) { var parentSchema = new mongoose.Schema({ parentSchema.pre('validate', function(next) { parentSchema.pre('save', function(next) { |
查找子文档
每个子文档都有一个默认的_id 。Mongoose document数组有一个特别的id方法,这个方法只要传入_id 就能返回文档数组中特定文档。
var doc = parent.children.id(_id); |
添加子文档到数组
Mongoose 数组方法有 push、 unshift、 addToSet、 及其他:
var Parent = mongoose.model('Parent'); // create a comment parent.save(function (err) { |
create 方法可以新建子文档但不加入数组。
var newdoc = parent.children.create({ name: 'Aaron' }); |
删除子文档
每个子文档都有 remove方法。另外,对于子文档数组,有一个等效方法 .pull()。 对于单个嵌套子文档,remove()与把这个文档的值设为null等效。
// 等效于 `parent.children.pull(_id)` parent.children.id(_id).remove(); // 等效于 `parent.child = null` parent.child.remove(); parent.save(function (err) { if (err) return handleError(err); console.log('the subdocs were removed'); }); |
掌握了这些就能应付这个小项目了,如果要看详细api请参考官方文档。