node.js – (mongoose / promises)如何检查文档是否是使用带有upsert的findOneAndUpdate创建的

前端之家收集整理的这篇文章主要介绍了node.js – (mongoose / promises)如何检查文档是否是使用带有upsert的findOneAndUpdate创建的前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
考虑这段代码,我需要创建或更新特定文档.
InBox.model.findOneAndUpdate({ number: req.phone.number },{
    number: req.phone.number,country: req.phone.country,token: hat(),appInstalled: true
},{ new: true,upsert: true }).then(function(inBox){
    /*
       do something here with inBox,but only if the inBox was created (not updated)
    */
});

mongoose是否有能力区分是否创建或更新了文档?我需要new:true因为我需要在收件箱中调用函数.

解决方法

对于mongoose的 .findOneAndUpdate()或任何.findAndModify()核心驱动程序变体,实际的回调签名具有“三个”参数:
function(err,result,raw)

第一个是任何错误响应,然后修改或原始文档取决于选项,第三个是发布语句的写入结果.

第三个参数应该像这样返回数据:

{ lastErrorObject:
   { updatedExisting: false,n: 1,upserted: 55e12c65f6044f57c8e09a46 },value: { _id: 55e12c65f6044f57c8e09a46,number: 55555555,country: 'US',token: "XXX",appInstalled: true,__v: 0 },ok: 1 }

使用一致字段作为lastErrorObject.updatedExisting是true / false,具体取决于是否发生upsert的结果.请注意,当此属性为false时,还有一个“upserted”值包含新文档的_id响应,但是当它为true时不包含.id响应值.

因此,您将修改您的处理以考虑第三个条件,但这仅适用于回调而不是承诺:

InBox.model.findOneAndUpdate(
    { "number": req.phone.number },{ 
      "$set": {
          "country": req.phone.country,"token": hat(),"appInstalled": true
      }
    },{ "new": true,"upsert": true },function(err,doc,raw) {

      if ( !raw.lastErrorObject.updatedExitsing ) {
         // do things with the new document created
      }
    }
);

我强烈建议你在这里使用update operators而不是原始对象,因为原始对象将始终覆盖整个文档,但像$set这样的运算符只会影响列出的字段.

还注意到语句的任何匹配“查询参数”都会在新文档中自动分配,只要它们的值是未找到的完全匹配即可.

鉴于使用promise似乎没有出于某种原因返回附加信息,那么除了设置{new:false}之外的其他承诺并没有看到这是可能的,并且基本上当没有返回文档时它是新的.

无论如何,您都希望插入所有文档数据,因此不一定非常需要返回的数据.事实上,本机驱动程序方法在核心处理这个问题,并且只有在发生upsert时才会响应“upserted”_id值.

这真的归结为本网站讨论的另一个问题,在:

Can promises have multiple arguments to onFulfilled?

这实际上归结为在promise响应中解决多个对象,这在本地特征化中没有直接支持,但是那里列出了一些方法.

所以,如果你实现Bluebird promises并在那里使用.spread()方法,那么一切都很好:

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

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

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

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

async.series(
  [
    function(callback) {
      Test.remove({},callback);
    },function(callback) {
      var promise = Test.findOneAndUpdateAsync(
        { "name": "Bill" },{ "$set": { "name": "Bill" } },"upsert": true }
      );

      promise.spread(function(doc,raw) {
        console.log(doc);
        console.log(raw);
        if ( !raw.lastErrorObject.updatedExisting ) {
          console.log( "new document" );
        }
        callback();
      });
    }
  ],function(err) {
    if (err) throw err;
    mongoose.disconnect();
  }
);

当然,这会返回两个对象,然后您可以始终如一地访问:

{ _id: 55e14b7af6044f57c8e09a4e,name: 'Bill',__v: 0 }
{ lastErrorObject:
   { updatedExisting: false,upserted: 55e14b7af6044f57c8e09a4e },value: { _id: 55e14b7af6044f57c8e09a4e,ok: 1 }

以下是演示正常行为的完整列表:

var async = require('async'),'test');

async.series(
  [
    function(callback) {
      Test.remove({},function(callback) {
      Test.findOneAndUpdate(
        { "name": "Bill" },"upsert": true }
      ).then(function(doc,function(err) {
    if (err) throw err;
    mongoose.disconnect();
  }
);

对于记录,本机驱动程序本身没有此问题,因为响应对象实际上是除了任何错误之外返回的唯一对象:

var async = require('async'),mongodb = require('mongodb'),MongoClient = mongodb.MongoClient;

MongoClient.connect('mongodb://localhost/test',db) {

  var collection = db.collection('test');

  collection.findOneAndUpdate(
    { "name": "Bill" },{ "upsert": true,"returnOriginal": false }
  ).then(function(response) {
    console.log(response);
  });
});

所以总是这样:

{ lastErrorObject:
   { updatedExisting: false,upserted: 55e13bcbf6044f57c8e09a4b },value: { _id: 55e13bcbf6044f57c8e09a4b,name: 'Bill' },ok: 1 }

猜你在找的Node.js相关文章