【问题标题】:mongoose to determine update-upsert is doing insert or updatemongoose 确定 update-upsert 是在做插入还是更新
【发布时间】:2014-12-29 17:49:51
【问题描述】:

我想测试用于更新的“upsert”选项是否正常。所以我用相同的键将一个对象“插入”到 mongodb 中两次。但是它没有显示插入的消息。我错过了什么吗?

(mongodb:v2.6.3;猫鼬:3.8.15)

Member.findOneAndRemove({user_id: 1},
    function (err, doc) {
        if (!err) onsole.log(doc ? 'deleted' : 'not found');
}); // -> deleted, make sure user_id = 1 doesn't exist

Member.update({user_id: 1}, 
    {$set: {name: "name1"}}, 
    {upsert: true, new: false}, // new : false, so that I can detect original doc is null then know it's a new one.
    function (err, doc) {
    if (!err) {
        console.log(doc ? 'updated' : 'inserted')
    }
}); // -> updated ? But it shoule be inserted, right ?

Member.update({user_id: 1}, 
    {$set: {name: "name2"}}, 
    {upsert: true, new: false},
    function (err, doc) {
    if (!err) {
        console.log(doc ? 'updated' : 'inserted')
    }
}); // -> updated, yes, no problem.

感谢您的任何提示。

============回答=============

使用 .findOneAndUpdate 而不是 .update ! 此外,确保选项是 {upsert: true, new: false}, 这样回调的第二个参数(doc)可以是原始文档以防万一。

【问题讨论】:

    标签: javascript node.js mongodb mongoose mongodb-query


    【解决方案1】:

    猫鼬中的.update() 方法接受三个回调参数,分别是errnumAffectedraw 响应。使用“原始”对象查看发生了什么:

    Member.update({user_id : 1}, 
        {$set : {name:"name1"}}, 
        {upsert : true }, 
        function (err, numAffected, raw) {
        if (!err) {
            console.log(raw)
        }
    });
    

    你会看到这样的结构:

    { ok: true,
      n: 1,
      updatedExisting: false,
      upserted: [ { index: 0, _id: 5456fc7738209001a6b5e1be } ] }
    

    因此,创建的任何新文档总是有 n 和 'updatedExistingkeys available, where the second is false on upserts and true otherwise.upsertedwill contain the_id` 值。

    至于n 或“numAffected”,这基本上始终为 1,其中文档在旧版写入关注响应下匹配。

    您可以使用批量操作表单在 MongoDB 2.6 及更高版本中查看新的 WriteResult 响应:

    var bulk = Member.collection.initializeOrderedBulkOp();
    bulk.find({user_id : 1}.upsert().update({$set : {name:"name1"}});
    bulk.execute(err,result) {
       console.log( JSON.stringify( result, undefined, 2 ) );
    }
    

    在第一次迭代中你会得到这样的结果:

    {
      "ok": 1,
      "writeErrors": [],
      "writeConcernErrors": [],
      "nInserted": 0,
      "nUpserted": 1,
      "nMatched": 0,
      "nModified": 0,
      "nRemoved": 0,
      "upserted": [
        {
          "index": 0,
          "_id": "5456fff138209001a6b5e1c0"
        }
      ]
    }
    

    第二个参数是这样的:

    {
      "ok": 1,
      "writeErrors": [],
      "writeConcernErrors": [],
      "nInserted": 0,
      "nUpserted": 0,
      "nMatched": 1,
      "nModified": 0,
      "nRemoved": 0,
      "upserted": []
    }
    

    并且文档只会在实际发生更改的地方被标记为“已修改”。

    所以无论如何,.update() 操作不会返回修改后的文档或原始文档。那就是.findOneAndUpdate() 方法,它是一个围绕基本.findAndModify() 的猫鼬包装器,它执行原子操作。 .update() 方法通常用于批量操作,因此不返回文档内容。

    【讨论】:

    • 我刚刚完成了 .findOneAndUpdate 测试,是的,它显示了我想要的和你提到的。我仍然可以使用 .update() 来实现相同的目标。但是 .findOneAndUpdate 在这种情况下是最好和最简单的方法。非常感谢。
    • @Kevin .findOneAndUpdate() 实际上并没有告诉您是否“插入”了某些内容。尤其是设置了“新”选项(这是猫鼬的默认设置)。你只能通过"new": false 来判断,然后从那里向后工作。
    • 我应该说使用带有选项 {upsert: ture, new: false} 的 .findOneAndUpdate()。仅 .findOneAndUpdate() 调用仍会使答案令人困惑。谢谢提醒!
    • @NeilLunn 你能解释一下“从那里向后工作”是什么意思吗?据我所知,设置 "new": false 并不能说明记录是插入还是更新。实际上,您的意思是在旧文档中查找“_id”字段,如果存在,则假设记录更新了吗?
    【解决方案2】:

    关于原始问题的 OPs 编辑以使用 .findOneAndUpdate,您现在还可以传递 rawResult: true 参数,该参数将返回文档以及您通常从运行 .update 获得的数据,即:

    { 
      updatedExisting: true,
      n: 1,
      ok: 1
    }
    

    这应该足以回答知道您是插入还是插入的原始问题。

    我发现使用 .findOneAndUpdate 的 upserts 通常需要这组选项:

      {
        upsert: true,
        new: true,
        runValidators: true,
        setDefaultsOnInsert: true,
        rawResult: true,
      }
    

    【讨论】:

      猜你喜欢
      • 2010-10-18
      • 2011-04-09
      • 2016-04-18
      • 1970-01-01
      • 2013-09-30
      • 1970-01-01
      • 2018-09-26
      • 2015-01-14
      • 1970-01-01
      相关资源
      最近更新 更多