【问题标题】:How to check whether a document was inserted or updated when using findOneAndUpdate?使用 findOneAndUpdate 时如何检查文档是否被插入或更新?
【发布时间】:2015-11-22 11:52:27
【问题描述】:
Chatrooms.findOneAndUpdate({Roomname: room.Roomname},{ $setOnInsert: {status: true, userNum: 1}}, {new: true, upsert: true}, function(err, doc) {
    if(err) console.log(err);

    console.log("DOC " + doc)

    if(doc.status) {
        // FOUND ROOM SATTUS IS TRUE LOGIC 
        console.log(doc);
        // return callback(true)
    }
 });

上面的查询将返回给我更新或插入的实际文档,但我无法准确检查它是哪一个。如果我进行更新而不是 findOneandUpdate 我会返回这个

{
    ok: 1,
    nModified: 0,
    n: 1,
    upserted: [ { index: 0, _id: 55df883dd5c3f7cda6f84c78 } ]
} 

如何同时返回文档和写入结果,或者至少返回写入结果中的 upserted 字段。

【问题讨论】:

  • 如果它是“upserted”,那么文档中唯一可能存在的内容就是您在操作中发送的内容。在这种情况下,“RoomName”、“status”和“userNum”字段以及您在此处指定的所有内容。除了您发送的内容之外,唯一可能创建的是_id 值。所以这就是为什么那是唯一返回的东西。理解?您不需要返回任何东西,因为您已经拥有所有值。
  • 对,但是对于 findOneAndUpdate 如果我说 new:true ,是否无法区分返回的文档是插入还是找到?但是,如果我不包括 new:true 那么在这种情况下 doc 将在找不到 doc 时返回 null 然后我假设它已插入但我想知道是否有更好的方法来查看它
  • 你显然不明白。再读一遍我说的话。您发送三个字段的值,您会被告知创建了一个新文档以及该文档的新 _id。除了您要求它设置的值之外,不会创建其他字段。您已经知道这些值,因此返回仅包含这些值的文档是没有意义的。这就是它的工作原理。
  • 我没有得到仅用于更新的 findOneAndUpdate 的写入结果对象 我想知道如何将 findOneAndUpdate 与文档一起获取。
  • 但我认为这是不可能的

标签: node.js mongodb mongoose mongodb-query


【解决方案1】:

恐怕使用 FindOneAndUpdate 不能做你想做的事,因为它没有中间件和设置器,并且在文档中提到了它:

虽然在使用 findAndModify 帮助器时将值转换为适当的类型,但以下内容不适用:

  • 默认值
  • 二传手
  • 验证器
  • 中间件

http://mongoosejs.com/docs/api.html 在 findOneAndUpdate 中搜索它
如果您想获取更新前的文档和更新后的文档,您可以这样做:

Model.findOne({ name: 'borne' }, function (err, doc) {
if (doc){ 
  console.log(doc);//this is ur document before update
  doc.name = 'jason borne';
  doc.save(callback); // you can use your own callback to get the udpated doc
}
})

希望对你有帮助

【讨论】:

  • 谢谢,但我目前的问题是我无法在findOneAndUpdate的回调范围内访问room.roomname
  • 正如我在回答中提到的,您无法使用 findOneAndUpdate 访问文档,因为它没有验证器,这不会返回您刚刚更新的文档。我建议您阅读文档,其中包含大量有关 API 的信息。
  • 如果我执行 true:new,它会返回它,但我不知道它是被插入还是被找到。
  • 哦,等一下,你能登录房间吗。房间名可能变量为空,所以你没有得到更新
  • 是的,变量 doc 为空,在这种情况下,我想返回 room.Roomname 但超出范围?
【解决方案2】:

我不知道这是如何完全偏离轨道的,但是对于所有 .XXupdate() 方法,始终存在“第三个”参数响应,这基本上是来自驱动程序的原始响应。这总是告诉您文档是否“更新”:

Chatrooms.findOneAndUpdate(
   { "Roomname": room.Roomname },
   { "$setOnInsert": { 
      "status": true, "userNum": 1
   }},
   { "new": true, "upsert": true },
   function(err, doc,raw) {
    if(err) console.log(err);

    // Check if upserted
    if ( raw.lasErrorObject.n == 1 && !raw.lastErrorObject.updatedExisting ) {
        console.log("upserted: %s", raw.lastErrorObject.upserted);
    }

    console.log("DOC " + doc)

    if (doc.status) {
        // FOUND ROOM SATTUS IS TRUE LOGIC 
        console.log(doc);
        // return callback(true)
    }
});

这将告诉您刚刚更新插入的文档的_id

来自“原始”响应中的类似内容:

{ lastErrorObject:
   { updatedExisting: false,
     n: 1,
     upserted: 55e12c65f6044f57c8e09a46 },
  value: { _id: 55e12c65f6044f57c8e09a46, 
           status: true,
           userNum: 1
           __v: 0 },
  ok: 1 }

完整的可重复列表:

var async = require('async'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/test');

var testSchema = new Schema({
  name: String
});

var Test = mongoose.model('Test', testSchema, 'test');

async.series(
  [
    function(callback) {
      Test.remove({},callback);
    },
    function(callback) {
      async.eachSeries(
        ["first","second"],
        function(it,callback) {
          console.log(it);
          Test.findOneAndUpdate(
            { "name": "Bill" },
            { "$set": { "name": "Bill" } },
            { "new": true, "upsert": true },
            function(err,doc,raw) {
              console.log(raw),
              console.log(doc),
              callback(err);
            }
          );
        },
        callback
      );
    }
  ],
  function(err) {
    if (err) throw err;
    mongoose.disconnect();
  }
);

哪些输出:

first
{ lastErrorObject:
   { updatedExisting: false,
     n: 1,
     upserted: 55e2a92328f7d03a06a2dd6b },
  value: { _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 },
  ok: 1 }
{ _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 }
second
{ lastErrorObject: { updatedExisting: true, n: 1 },
  value: { _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 },
  ok: 1 }
{ _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 }

【讨论】:

  • raw 对我来说是未定义的。知道为什么吗?
  • @SarodhUggalla 不可能。只有在没有匹配或 upsert 时,它才是未定义的。使用upsert:true,总会有回应。那是因为这是猫鼬首先得到响应的地方。你做错了/不同。
  • Chatrooms.findOneAndUpdate({Roomname: RoomHash.roomhash},{ $setOnInsert: { userNum: 1, status: true}}, {new: true,upsert: true}, function(err, doc, raw) { console.log("DOC: %j" , doc); console.log("RAW: %j", raw); if(err) console.log(err);
  • 据我所知完全一样。
  • @SarodhUggalla 你的猫鼬版本是什么?
【解决方案3】:

好的,所以我的主要问题是我无法获取插入的文档的 _id,而无法检查它是否已更新/找到或插入。但是我了解到您可以生成自己的 ID。

id = mongoose.Types.ObjectId();    
Chatrooms.findOneAndUpdate({Roomname: room.Roomname},{ $setOnInsert: {_id: id, status: true, userNum: 1}}, {new: true, upsert: true}, function(err, doc) {
        if(err) console.log(err);

        if(doc === null) {

           // inserted document logic 
           // _id available for inserted document via id 
        } else if(doc.status) {

         // found document logic 
        }
     });

更新

Mongoose API v4.4.8

passRawResult:如果为 true,则将来自 MongoDB 驱动程序的原始结果作为第三个回调参数传递。

【讨论】:

  • 你不需要这样做。
【解决方案4】:

Mongoose 4.1.10 版有一个名为passRawResult 的选项,如果设置为true,则会传递raw 参数。省略此选项似乎默认为 false 并导致 raw 始终为 undefined

passRawResult:如果为真,则传递来自 MongoDB 驱动程序的原始结果 作为第三个回调参数

http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate

【讨论】:

    【解决方案5】:

    截至 2019 年 8 月 8 日(Mongoose 版本 5.6.9),要设置的属性是“rawResult”而不是“passRawResult”:

    M.findOneAndUpdate({}, obj, {new: true, upsert: true, rawResult:true}, function(err, d) {
        if(err) console.log(err);
        console.log(d);
    });
    

    输出:

    { lastErrorObject:
       { n: 1,
         updatedExisting: false,
         upserted: 5d4befa6b44b48c3f2d21c75 },
      value: { _id: 5d4befa6b44b48c3f2d21c75, rating: 4, review: 'QQQ' },
      ok: 1 }
    

    请注意,结果是作为回调的第二个参数而不是第三个参数返回的。文档可以通过d.value来检索。

    【讨论】:

      猜你喜欢
      • 2012-09-16
      • 2014-02-26
      • 2023-03-11
      • 2015-11-23
      • 2021-06-24
      • 2018-04-03
      • 2017-08-13
      • 1970-01-01
      • 2018-03-05
      相关资源
      最近更新 更多