有时我需要在DB中存在一个文档,并且很高兴能够使用现有文档,或者如果文档丢失则创建文档,并使用新文档。
这似乎是一个相当常见的用例,但我已查看了Mongoose docs,但我无法找到任何内容。
Mongoose收集方法,例如findOneAndUpdate()
和update()
与upsert: true
关于修改文档 - 我不希望修改文档(如果存在),只需获取对它的引用。
示例 :(为@neillunn添加)我想添加一个用户,其中包含对名称为'的公司的引用。是' foo'。在此之前,我希望使用{name: 'foo'}
查找公司,并在不存在的情况下创建公司。
示例2 :(为@neillunn添加)代码我现在用来处理示例场景:
// Find or create an an instance and return a cb with a reference to it.
var findOrCreate = function(model, criteria, cb){
model.update(criteria, criteria, {upsert: true}, function(err, numberAffected, raw){
if ( ! raw.updatedExisting ) {
console.log('Created instance')
} else {
console.log('Found existing instance')
}
model.findOne(criteria, cb)
})
}
注意:findOneAndUpdate()
无法正常工作,因为它会尝试修改现有文档,并获得重复的密钥错误索引'
答案 0 :(得分:11)
如评论中所述,有一个mongoose插件可以执行此操作: http://github.com/drudge/mongoose-findorcreate
This Thread还描述了一种在没有插件的情况下实现此目的的方法。我只是不确定它是否适用于猫鼬。
答案 1 :(得分:2)
Mongoose has an inbuilt findOneAndUpdate
function可以找到,如果数据不存在,它将创建数据。基本上,下面是它的完成方式:
var modelDoc = new MyModel({ foo: 'bar' });
MyModel.findOneAndUpdate(
{foo: 'bar'}, // find a document with that filter
modelDoc, // document to insert when nothing was found
{upsert: true, new: true, runValidators: true}, // options
function (err, doc) { // callback
if (err) {
// handle error
} else {
// handle document
}
}
);
options
参数对于使插入工作必不可少。`
通过设置upsert: true
,如果{foo: 'bar'}
过滤器未找到结果,则您命令MongoDB将modelDoc文档实际添加到集合中。
new: true
选项更改了回调函数中返回的内容。如果为false,则doc将在更新之前包含该文档(或在插入之前为null)。如果为true,则doc将在更新或创建后包含文档。虽然false是默认选项,但我想大多数人实际上还是希望它为true。
如果您想让Mongoose运行验证程序,必须设置runValidators: true
选项。默认情况下,使用findOneAndUpdate()
时将不执行这些操作。
答案 2 :(得分:1)
非常有用的解决方案:https://stackoverflow.com/a/7592756/4025963:
var Counters = new Schema({
_id: String,
next: Number
});
Counters.statics.findAndModify = function (query, sort, doc, options, callback) {
return this.collection.findAndModify(query, sort, doc, options, callback);
};
var Counter = mongoose.model('counters', Counters);
Counter.findAndModify({ _id: 'messagetransaction' }, [], { $inc: { next: 1 } }, {}, function (err, counter) {
if (err) throw err;
console.log('updated, counter is ' + counter.next);
});
习惯承诺时更有趣:
Counters.statics.findAndModify =
function findAndModify(query, sort, update, options, callback) {
const promised = q.nbind(this.collection.findAndModify, this.collection);
return promised(query || {}, sort || [], update || {}, options, callback);
};