如何在Mongoose中创建/查找?

14
有时我需要在数据库中存在一个文档,可以使用现有的文档,也可以创建新文档并使用它。
这似乎是一个相当普遍的用例,但我查看了Mongoose文档,没有找到相关内容。
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()`不起作用,因为它会尝试修改现有文档,并获得“重复键错误索引”。

并不是很清楚。你正在关注正确的事情,但为什么你只想要基本上“查找”它是否存在,并且如果不存在就“修改/插入”呢?这种差异似乎不言自明。也许更好地解释一下你的用例。 - Neil Lunn
所以你基本上想要自动关联吗?鉴于mongoose不正式或程序上支持关系,我认为你需要执行两个查询才能实现这一点。 - David Losert
@Charminbear 不是关系,只是根据需要找到或创建。在我的例子中,我找到/创建了一个公司实例,因为我需要引用 company._id,但这只是当前的用例。 - mikemaccana
1
@mikemaccana:https://github.com/drudge/mongoose-findorcreate 你在寻找这样的东西吗? - David Losert
这个问题的解决方案非常有用:https://dev59.com/wGs05IYBdhLWcg3wR_63#7592756 - David
3个回答

11

5

Mongoose内置了findOneAndUpdate函数,可用于查找数据,如果数据不存在,则会创建该数据。基本上以下是实现的方式:

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,您可以命令MongoDB在{foo: 'bar'}过滤器未找到结果时将modelDoc文档添加到集合中。 new: true选项更改回调函数中返回的内容。如果为false,则doc将包含更新之前的文档(或在插入之前为空)。如果为true,则doc包含更新或创建后的文档。虽然false是默认选项,但我想大多数人实际上都更喜欢它为true。
如果要Mongoose运行验证器,则必须设置runValidators: true选项。使用findOneAndUpdate()时,默认情况下不会执行这些操作。

从文档中得知:“使用upsert:true选项与findOneAndUpdate()方法一起使用,并且在查询字段上未使用唯一索引,使用类似查询字段的多个findOneAndUpdate()操作可能会在某些情况下导致重复文档被插入。” - AlexPi

1

这里有一个非常有用的解决方案:https://dev59.com/wGs05IYBdhLWcg3wR_63#7592756

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);
});

更有趣的是,当用于 promises 时:
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);
    };

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接