mongoose确定update-upsert正在进行插入或更新

Kev*_*vin 3 javascript mongoose mongodb node.js mongodb-query

我想测试更新的"upsert"选项是否正常.所以我用相同的键将一个对象"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.
Run Code Online (Sandbox Code Playgroud)

谢谢你的提示.

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

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

Pau*_*oud 7

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

{ 
  updatedExisting: true,
  n: 1,
  ok: 1
}
Run Code Online (Sandbox Code Playgroud)

这应该足以回答最初的问题,即知道您是插入还是更新插入。

我发现这组选项对于使用以下命令进行更新插入通常是理想的.findOneAndUpdate

  {
    upsert: true,
    new: true,
    runValidators: true,
    setDefaultsOnInsert: true,
    rawResult: true,
  }
Run Code Online (Sandbox Code Playgroud)


Nei*_*unn 5

.update()mongoose中的方法对回调有三个参数err,即numAffected,raw响应和响应.使用"原始"对象查看发生的情况:

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

你会看到这样的结构:

{ ok: true,
  n: 1,
  updatedExisting: false,
  upserted: [ { index: 0, _id: 5456fc7738209001a6b5e1be } ] }
Run Code Online (Sandbox Code Playgroud)

因此,创建的任何新文档始终都有n'updatedExisting keys available, where the second is false on upserts and true otherwise.upserted will 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 ) );
}
Run Code Online (Sandbox Code Playgroud)

在第一次迭代中你得到这样的东西:

{
  "ok": 1,
  "writeErrors": [],
  "writeConcernErrors": [],
  "nInserted": 0,
  "nUpserted": 1,
  "nMatched": 0,
  "nModified": 0,
  "nRemoved": 0,
  "upserted": [
    {
      "index": 0,
      "_id": "5456fff138209001a6b5e1c0"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

第二个具有相同的参数,如下所示:

{
  "ok": 1,
  "writeErrors": [],
  "writeConcernErrors": [],
  "nInserted": 0,
  "nUpserted": 0,
  "nMatched": 1,
  "nModified": 0,
  "nRemoved": 0,
  "upserted": []
}
Run Code Online (Sandbox Code Playgroud)

并且文档只会被标记为"已修改",其中某些内容实际上已更改.

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