sql >> Databáze >  >> NoSQL >> MongoDB

(mongoose/promises) Jak zkontrolujete, zda byl dokument vytvořen pomocí findOneAndUpdate s upsert

V případě .findOneAndUpdate() nebo kteroukoli z .findAndModify() varianty základního ovladače pro mongoose, vlastní signatura zpětného volání má "tři" argumenty:

 function(err,result,raw)

První je jakákoli chybová odpověď, poté upravený nebo původní dokument v závislosti na možnostech a třetí, která je výsledkem zápisu vydaného prohlášení.

Tento třetí argument by měl vrátit data podobná tomuto:

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

S konzistentním polem jako lastErrorObject.updatedExisting být buď true/false v závislosti na výsledku, zda došlo k upsert. Všimněte si, že existuje také hodnota "upserted" obsahující _id odpověď pro nový dokument, když je tato vlastnost false , ale ne, když je true .

Jako takový byste pak upravili své zpracování tak, aby bylo možné vzít v úvahu třetí podmínku, ale to funguje pouze se zpětným voláním, nikoli se slibem:

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

Kde také důrazně doporučuji používat operátory aktualizací spíše než nezpracované objekty, protože nezpracovaný objekt vždy přepíše celý dokument, přesto operátory jako $set stačí ovlivnit uvedená pole.

Také je třeba poznamenat, že všechny odpovídající "argumenty dotazu" k příkazu jsou v novém dokumentu automaticky přiřazeny, pokud je jejich hodnota přesná shoda, která nebyla nalezena.

Vzhledem k tomu, že se zdá, že použití slibu z nějakého důvodu nevrací dodatečné informace, nechápu, jak je to možné s jiným slibem než nastavením { new: false} a v zásadě, když není vrácen žádný dokument, je to nový.

Očekává se, že všechna data dokumentu budou stejně vložena, takže to není tak, že byste je skutečně potřebovali vrátit. Je to ve skutečnosti způsob, jakým s tím nativní metody ovladače v jádru zacházejí a reagují pouze "upserted" _id hodnotu, když dojde k upsert.

To se skutečně týká jiného problému diskutovaného na tomto webu pod:

Můžou mít sliby pro onFulfilled více argumentů?

Tam, kde jde skutečně o rozlišení více objektů v příslibové odpovědi, což je něco, co není přímo podporováno v nativní specifikaci, ale jsou zde uvedeny přístupy.

Pokud tedy implementujete sliby Bluebird a použijete .spread() metoda tam, pak je vše v pořádku:

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

Což samozřejmě vrátí oba objekty a vy můžete přistupovat konzistentně:

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

Zde je úplný seznam demonstrující normální chování:

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

Pro záznam, nativní ovladač sám o sobě tento problém nemá, protože objekt odpovědi je ve skutečnosti jediným objektem vráceným kromě jakékoli chyby:

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

Takže je to vždy něco takového:

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


  1. proč je to tak pomalé se 100 000 záznamy při použití pipeline v redis?

  2. Vrátí skutečný typ pole v MongoDB

  3. Vystavte MongoDB na Kubernetes s externím clusterem StatefulSets

  4. Jak se správně připojit ke clusteru Atlas M0 (Free Tier) pomocí ovladače Java?