sql >> データベース >  >> NoSQL >> MongoDB

(mongoose / promises)ドキュメントがupsertでfindOneAndUpdateを使用して作成されたかどうかをどのように確認しますか

    .findOneAndUpdate()の場合 または.findAndModify()のいずれか マングースのコアドライバーバリアントである実際のコールバックシグネチャには、「3つの」引数があります。

     function(err,result,raw)
    

    最初はエラー応答であり、次にオプションに応じて変更されたドキュメントまたは元のドキュメントであり、3番目は発行されたステートメントの書き込み結果です。

    その3番目の引数は、次のようなデータを返す必要があります。

    { 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のいずれかである アップサートが発生したかどうかの結果によって異なります。 _idを含む「upserted」値もあることに注意してください このプロパティがfalseの場合の新しいドキュメントの応答 、ただし、trueの場合はそうではありません 。

    そのため、3番目の条件を考慮するように処理を変更しますが、これはコールバックでのみ機能し、promiseでは機能しません。

    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 リストされたフィールドに影響を与えるだけです。

    また、ステートメントに一致する「クエリ引数」は、それらの値が見つからなかった完全一致である限り、新しいドキュメントに自動的に割り当てられることに注意してください。

    何らかの理由でpromiseを使用しても追加情報が返されないように思われる場合は、{ new: false}を設定する以外のpromiseでこれがどのように可能かを確認しないでください。 基本的に、ドキュメントが返されない場合は、新しいドキュメントです。

    とにかくすべてのドキュメントデータが挿入されることが期待されているので、とにかくそのデータを返す必要があるわけではありません。実際、ネイティブドライバーメソッドがコアでこれを処理し、「upserted」_idでのみ応答する方法です。 アップサートが発生したときの値。

    これは、このサイトで説明されている別の問題に帰着します。

    プロミスはonFulfilledに対して複数の引数を持つことができますか?

    これが実際にpromise応答での複数のオブジェクトの解決に帰着する場合、これはネイティブの仕様では直接サポートされていませんが、そこにリストされているアプローチがあります。

    したがって、Bluebirdのpromiseを実装し、.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. mongoとupsertの配列を更新します

    2. マングースfindOneの使い方

    3. アイソデートを数値に変換する

    4. mongodbのネストされたオブジェクトのフィールドを更新する方法は?