Mongoose 常用API及常见问题汇总

2,167 阅读4分钟

最近又在用express+Mongoose,为方便之后查询及问题汇总,在这里简单记录下

安装和链接


npm install mongoose 

Mongoose基本概念


Schema: 表定义模板

Model: 类似关系数据库表,封装成具有一些集合操作的对象

let schema = new mongoose.Schema({
    id: {
        type: Number,
        required: true
    },
    name: {
        type: String,
        required: true
    },
    age: {
        type: Number
    }
}, {
    versionKey: false,
    timestamps: {
        createdAt: 'createTime', updatedAt: 'updateTime', lastLoginDate: 'lastLoginDate'
    }
});

let userModel = mongoose.model('user', schema);

常用API


一说到数据库,最先想到的就是增删改查。

新增

Model.create(): 插入一个或多个文档

Model.create(docs[, options][, callback])

如果插入一个文档,则传入一个对象即可;如果插入多个文档,则传入一个数组

let doc = {
    id: 1,
    name: 'shan-er',
    age: 1
};
userModel.create(doc, (error) => {})
ModelEntity.save():只针对当前文档实例

Document.prototype.save([options][, callback])

let doc = {
    id: 1,
    name: 'shan-er',
    age: 1
};
let mongooseEntity = new userModel(doc);
mongooseEntity.save((error) => {})
Model.insertMany()

Model.insertMany(docs[, options][, callback])

多条数据插入,将多条数据一次性插入,相对于循环使用create保存会更加快。

Mongoose 在向 MongoDB 发送 insertMany 之前会验证每个文档。因此,如果一个文档出现验证错误,则不会保存任何文档,除非将 ordered 选项设置为 false。

let docs = [{
    id: 1,
    name: 'shan-er',
    age: 1
}, {
    id: 2,
    name: 'shan-er-2',
    age: 1
}];
userModel.insertMany(docs, (error, docs) => {})
create()与save()区别

Model.create()内部调用了<model_instance>.save()方法,并且做了一些额外的封装。

两者主要的区别在于:

  • Model.create()可以同时保存一组文档。

  • .save()只针对当前文档实例。

create(docs) 为 docs 中的每个文档执行 MyModel(doc).save()。

查找

Model.find()

Model.find(conditions, [fields], [options], [callback])

userModel.find({age: 1}, (err, docs) => {
    // docs 是查询的结果数组
})

userModel.find({}, ['id','name'], (err, docs) => {
    // docs 此时只包含文档的部分键值
})
Model.findOne()

Model.findOne([conditions], [projection], [options], [callback])

与 Model.find 相同,但只返回单个文档

userModel.findOne({age: 1}, (err, doc) => {
    // doc 是单个文档
})
Model.findById()

Model.findById(id, [projection], [options], [callback])

与 findOne 相同,但它接收文档的 _id 作为参数,返回单个文档。_id 可以是字符串或 ObjectId 对象。

userModel.find(obj._id, (err, doc) => {
    // doc 是单个文档
})

修改

Model.Update()

Model.update(conditions, doc, [options], [callback])

conditions:查询条件;doc:需要修改的数据,不能修改主键(_id);options:控制选项;

该方法会匹配到所查找的内容进行更新,返回数据处理条数;

userModel.update({name: 'shan-er'}, {$set : {age : 2}, {upsert : true}, (err) => {})
Model.findOneAndUpdate()

Model.findOneAndUpdate([conditions], [update], [options], [callback])

该方法会根据查找去更新数据库,返回处理后的数据

需要获取数据就用findOneAndUpdate(),只需要修改数据而不关注修改后数据那就用update()

Model.findByIdAndUpdate()

Model.findByIdAndUpdate(id, [update], [options], [callback])

Model.updateMany():一次更新多条

Model.updateMany(conditions, doc, [options], [callback])

Model.updateOne(): 一次更新一条

Model.updateOne(conditions, doc, [options], [callback])

options说明
options有以下选项:
    new: bool - 默认为false。返回修改后的数据。
    upsert: bool - 默认为false。如果不存在则创建记录。
    fields: {Object|String} - 选择字段。类似.select(fields).findOneAndUpdate()。
    maxTimeMS: 查询用时上限。
    sort: 如果有多个查询条件,按顺序进行查询更新。
    runValidators: 如果值为true,执行Validation验证。
    setDefaultsOnInsert: 如果upsert选项为true,在新建时插入文档定义的默认值。
    passRawResult: 如果为真,将原始结果作为回调函数第三个参数。
.save()和update() 区别
  1. update比find之后save()效率高,因为这样不用读取整个文档。
  2. Mongoose的update是MongoDB的update,但是Mongoose的save可能是MongoDB的插入或是update。
  3. 关于save,mongoose会自动diff新文档,只更改更新部分。这有利于原子性。
  4. update不能触发中间件,validation默认不能,但是可以修改。

删除

Model.remove()

Model.remove(conditions[, options][, callback])

remove方法有两种使用方式,一种是用在模型上,另一种是用在模型实例上.

从集合中删除所有匹配 conditions 条件的文档

Model.findOneAndRemove()

Model.findOneAndRemove(conditions[, options][, callback])

Model.findByIdAndRemove()

Model.findOneAndRemove(id[, options][, callback])

Model.deleteOne()

Model.deleteOne(conditions[, options][, callback])

删除符合 conditions 条件的第一条文档。

Model.deleteMany()

Model.deleteMany(conditions[, options][, callback])

删除所有符合 conditions 条件的文档。

remove与deleteMany的区别

一样的效果,返回值不一样。

remove()并不会真正释放空间。需要继续执行 db.repairDatabase() 来回收磁盘空间。

官方建议使用deleteOne()、deleteMany()

常见问题汇总


用Mongoose得到的对象不能增加属性

原因:

因为Mongoose是個ODM (Object Document Mapper),类似于操作关系型数据库使用的ORM(Object Relational Mapper),我们使用Mongoose取到的数据的结构是要依赖于我们定义的schema结构的。增加的属性在schema中没有定义,所以我们在取到的结果中增加某个属性是无效的。

方法一:在Schema中增加属性

增加属性:一是直接增加属性值,入库;二若不想入库,可以使用virtual属性

schema.virtual('fullName').get(function () {
  return  this.firstName + this.lastName;
});

// 获取vitual属性,两种方式获取

// 1. doc._doc.fullName 获取

// 2. 
// userModel.set('toObject', {virtuals: true});
// userModel.set('toJSON', {virtuals: true});

方法二:clone结果值

例子略。

自动给集合名增加”s” ?

官网定义API

collection名称应该为第三个参数,若为缺省,会自动根据参数name的值以复数形式生成collection

let userModel = mongoose.model('user', schema, 'user');
小结

mongoose的相关的操作还有很多,在这里不详细列举了,至于常见问题可能会随时更新,做下记录~