MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

(mongoose/promises) Как да проверите дали документът е създаден с помощта на findOneAndUpdate с upsert

В случай на .findOneAndUpdate() или някой от .findAndModify() варианти на основен драйвер за mongoose, действителният подпис за обратно извикване има "три" аргумента:

 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. Обърнете внимание, че има и „upserted“ стойност, съдържаща _id отговор за новия документ, когато това свойство е false , но не и когато е true .

По този начин бихте променили обработката си, за да вземете предвид третото условие, но това работи само с обратно извикване, а не с обещание:

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

Където също силно препоръчвам да използвате оператори за актуализиране вместо необработени обекти тук, тъй като необработен обект винаги ще презапише целия документ, но оператори като $set просто засяга изброените полета.

Също така отбелязваме, че всички съвпадащи „аргументи на заявката“ към израза се присвояват автоматично в новия документ, стига тяхната стойност да е точно съвпадение, което не е намерено.

Като се има предвид, че използването на обещание изглежда не връща допълнителната информация по някаква причина, тогава не виждам как това е възможно с обещание, различно от настройката { new: false} и по принцип, когато не се връща документ, той е нов.

Имате всички данни от документа, които се очаква да бъдат вмъкнати така или иначе, така че не е като наистина да имате нужда от тези данни. Всъщност методите на родния драйвер се справят с това в основата и отговарят само с „upserted“ _id стойност при възникване на upsert.

Това всъщност се свежда до друг проблем, обсъждан на този сайт, под:

Могат ли обещанията да имат множество аргументи за onFulfilled?

Където това наистина се свежда до разделителната способност на множество обекти в отговор на обещание, което е нещо, което не се поддържа директно в спецификацията на родния код, но има изброени подходи там.

Така че, ако приложите обещанията на Bluebird и използвате .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" } },
        { "new": true, "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,
     n: 1,
     upserted: 55e14b7af6044f57c8e09a4e },
  value: { _id: 55e14b7af6044f57c8e09a4e, name: 'Bill', __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) {
      Test.findOneAndUpdate(
        { "name": "Bill" },
        { "$set": { "name": "Bill" } },
        { "new": true, "upsert": true }
      ).then(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();
  }
);

За протокола, самият нативен драйвер няма този проблем, тъй като обектът за отговор всъщност е единственият обект, върнат настрана от грешка:

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

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

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

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

Така че винаги е нещо подобно:

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


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB използва COLLSCAN, когато връща само _id

  2. MongoTemplate как да добавите повече от два orOperator в Query

  3. Mongo преобразува вградения документ в масив

  4. Отдалечено свързване към MongoDB http интерфейс на EC2 сървър

  5. Неуспешна инсталация на Mongodb при стартиране на mongod