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

FindAndUpdateドキュメントが本当に更新されたかどうかを確認する方法

    のようなものに更新が適用されたかどうかを確認する唯一の信頼できる方法 $ pull 基本的に、返されたドキュメントをチェックし、意図したデータが<かどうかを確認します。 code> $ pull まだそこにあるかどうか。

    これは、 "findAndUpdate"のいずれにも当てはまります。 さまざまなアクションがあり、それには正当な理由があります。また、単純な .update() 変更が実際に行われたかどうかを実際に「確実に」通知します。

    ケースをウォークスルーするには:

    返されたコンテンツを確認する

    これには基本的に、返されたドキュメントの配列を調べて、削除を要求したものが実際にそこにあるかどうかを確認することが含まれます。

    var pullId = "5961de06ea264532c684611a";
    
    Office.findByIdAndUpdate(1,
      { "$pull": { "branches": { "_id": pullId } } },
      { "new": true }
    ).then(office => {
      // Check if the supplied value is still in the array
      console.log(
        "Still there?: %s",
        (office.branches.find( b => b._id.toHexString() === pullId))
          ? true : false
      );
    }).catch(err => console.error(err))
    

    .toHexString() ObjectIdの実際の値を比較するため JavaScriptは「オブジェクト」との「同等性」を実行しないためです。 ObjectId にすでに「キャスト」されているものを提供する場合は、「左」と「右」の両方をチェックします。 値ですが、この場合、他の入力は「文字列」であることがわかります。

    .update()を使用するだけで、「信頼できる」

    ここで考慮すべきもう1つのケースは、返された変更されたデータがとにかく「本当に必要」であるかどうかに疑問を投げかけます。 .update() メソッドは、何かが実際に変更されたかどうかを示す結果を確実に返します:

    Office.update(
      { "_id": 1 },
      { "$pull": { "branches": { "_id": pullId } } },
    ).then(result => {
      log(result);
    }).catch(err => console.error(err))
    

    result ここでは次のようになります:

    {
      "n": 1,
      "nModified": 1,        // <--- This always tells the truth, and cannot lie!
      "opTime": {
        "ts": "6440673063762657282",
        "t": 4
      },
      "electionId": "7fffffff0000000000000004",
      "ok": 1
    }
    

    そして、その中で nModified 何かが「実際に更新された」かどうかの「真の」指標です。したがって、 1の場合 次に、 $ pull 実際には効果がありましたが、 0 アレイから実際に削除されたものはなく、変更されたものもありません。

    これは、メソッドが実際に更新されたAPIを使用しているためです。このAPIには、実際の変更を示す信頼できる結果があります。同じことが、 $ set> 提供された値がドキュメントにすでに存在する値と等しいため、実際には値は変更されませんでした。

    findAndModify Lies!

    ここで、ドキュメントを詳しく見るときに考えられるもう1つのケースは、実際に「生の結果」を調べて、ドキュメントが変更されたかどうかを確認することです。この仕様には、実際にはインジケーターがあります。

    問題は(Promisesでさらに作業が必要になるだけでなく)、結果が実際には真実ではないことです:

    var bogusId = "5961de06ea264532c684611a"; // We know this is not there!
    
    Promise((resolve,reject) => {
      Office.findByIdAndUpdate(1,
        { "$pull": { "branches": { "_id": bogusId } } },
        { "new": true, "passRawResult" },
        (err,result,raw) => {        // We cannot pass multiple results to a Promise
          if (err) reject(err);
          resolve({ result, raw });   // So we wrap it!
        }
      )
    })
    .then(response => log(response.raw))
    .catch(err => console.error(err));
    

    ここでの問題は、これが変更されるべきではないことを「知っている」場合でも、応答はそうではないと言うことです:

    {
      "lastErrorObject": {
        "updatedExisting": true,
        "n": 1                     // <--- LIES! IT'S ALL LIES!!!
      },
      "value": {
        "_id": 1,
        "name": "My Office",
        "branches": [
          {
            "address": "Third address",
            "isPrincipal": false,
            "_id": "5961de06ea264532c6846118"
          }
        ],
        "__v": 0
      },
      "ok": 1,
      "_kareemIgnore": true
    }
    

    そのため、コールバック応答から「3番目の」引数を取得するためのすべての作業を行った後でも、更新に関する正しい情報が通知されませんでした。

    結論

    したがって、1つのリクエストで「確実に」これを実行したい場合は(そしてできません ドキュメントが変更される可能性があるので、複数のリクエストで確実にそれを行います 間に! ) 次に、2つのオプションは次のとおりです。

    1. 返されたドキュメントをチェックして、削除したいデータがまだそこにあるかどうかを確認します。

    2. ドキュメントを返すのを忘れて、 .update()を信頼してください 常に「真実」を教えてくれます;)

    これらのどちらを使用するかは、アプリケーションの使用パターンによって異なりますが、「信頼できる」結果を返す2つの異なる方法です。

    リストの一部

    念のため、すべての例を調べて、実際に何が返されるかを示すリストを次に示します。

    const async = require('async'),
          mongoose = require('mongoose'),
          Schema = mongoose.Schema;
    
    mongoose.Promise = global.Promise;
    mongoose.set('debug',true);
    
    mongoose.connect('mongodb://localhost/test');
    
    const branchesSchema = new Schema({
      address: String,
      isPrincipal: Boolean
    });
    
    const officeSchema = new Schema({
      _id: Number,
      name: String,
      branches: [branchesSchema]
    },{ _id: false });
    
    const Office = mongoose.model('Office', officeSchema);
    
    function log(data) {
      console.log(JSON.stringify(data,undefined,2))
    }
    
    const testId = "5961a56d3ffd3d5e19c61610";
    
    async.series(
      [
        // Clean data
        (callback) =>
          async.each(mongoose.models,(model,callback) =>
            model.remove({},callback),callback),
    
        // Insert some data and pull
        (callback) =>
          async.waterfall(
            [
              // Create and demonstrate
              (callback) =>
                Office.create({
                  _id: 1,
                  name: "My Office",
                  branches: [
                    {
                      address: "Some street, that avenue",
                      isPrincipal: true
                    },
                    {
                      address: "Another address",
                      isPrincipal: false
                    },
                    {
                      address: "Third address",
                      isPrincipal: false
                    }
                  ]
                },callback),
    
              // Demo Alternates
              (office,callback) =>
                async.mapSeries(
                  [true,false].map((t,i) => ({ t, branch: office.branches[i] })),
                  (test,callback) =>
                    (test.t)
                      ? Office.findByIdAndUpdate(office._id,
                          { "$pull": { "branches": { "_id": test.branch._id } } },
                          { "new": true , "passRawResult": true },
                          (err,result,raw) => {
                            if (err) callback(err);
                            log(result);
                            log(raw);
                            callback();
                          })
                      : Office.findByIdAndUpdate(office._id,
                          { "$pull": { "branches": { "_id": test.branch._id } } },
                          { "new": true } // false here
                        ).then(result => {
                          log(result);
                          console.log(
                            "Present %s",
                            (result.branches.find( b =>
                              b._id.toHexString() === test.branch._id.toHexString() ))
                              ? true : false
                          );
                          callback();
                        }).catch(err => callback(err)),
                  callback
                )
            ],
            callback
          ),
    
        // Find and demonstate fails
        (callback) =>
          async.waterfall(
            [
              (callback) => Office.findOne({},callback),
    
              (office,callback) =>
                async.eachSeries([true,false],(item,callback) =>
                  (item)
                    ? Office.findByIdAndUpdate(office._id,
                        { "$pull": { "branches": { "_id": testId } } },
                        { "new": true, "passRawResult": true },
                        (err,result,raw) => {
                          if (err) callback(err);
                          log(result);
                          log(raw);
                          callback();
                        }
                      )
                    : Office.findByIdAndUpdate(office._id,
                        { "$pull": { "branches": { "_id": testId } } },
                        { "new": true }
                      ).then(result => {
                        console.log(result);
                        console.log(
                          "Present %s",
                          (result.branches.find( b =>
                            b._id.toHexString() === office.branches[0]._id.toHexString()))
                            ? true : false
                        );
                        callback();
                      })
                      .catch(err => callback(err)),
                  callback)
    
            ],
            callback
          ),
    
        // Demonstrate update() modified shows 0
        (callback) =>
          Office.update(
            {},
            { "$pull": { "branches": { "_id": testId } } }
          ).then(result => {
            log(result);
            callback();
          })
          .catch(err => callback(err)),
    
        // Demonstrate wrapped promise
        (callback) =>
          Office.findOne()
            .then(office => {
              return new Promise((resolve,reject) => {
                Office.findByIdAndUpdate(office._id,
                  { "$pull": { "branches": { "_id": testId } } },
                  { "new": true, "passRawResult": true },
                  (err,result,raw) => {
                    if (err) reject(err);
                    resolve(raw)
                  }
                );
              })
            })
            .then(office => {
              log(office);
              callback();
            })
            .catch(err => callback(err))
    
      ],
      (err) => {
        if (err) throw err;
        mongoose.disconnect();
      }
    );
    

    そしてそれが生成する出力:

    Mongoose: offices.remove({}, {})
    Mongoose: offices.insert({ _id: 1, name: 'My Office', branches: [ { address: 'Some street, that avenue', isPrincipal: true, _id: ObjectId("5961e5211a73e8331b44d74b") }, { address: 'Another address', isPrincipal: false, _id: ObjectId("5961e5211a73e8331b44d74a") }, { address: 'Third address', isPrincipal: false, _id: ObjectId("5961e5211a73e8331b44d749") } ], __v: 0 })
    Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961e5211a73e8331b44d74b") } } }, { new: true, passRawResult: true, upsert: false, remove: false, fields: {} })
    {
      "_id": 1,
      "name": "My Office",
      "__v": 0,
      "branches": [
        {
          "address": "Another address",
          "isPrincipal": false,
          "_id": "5961e5211a73e8331b44d74a"
        },
        {
          "address": "Third address",
          "isPrincipal": false,
          "_id": "5961e5211a73e8331b44d749"
        }
      ]
    }
    {
      "lastErrorObject": {
        "updatedExisting": true,
        "n": 1
      },
      "value": {
        "_id": 1,
        "name": "My Office",
        "branches": [
          {
            "address": "Another address",
            "isPrincipal": false,
            "_id": "5961e5211a73e8331b44d74a"
          },
          {
            "address": "Third address",
            "isPrincipal": false,
            "_id": "5961e5211a73e8331b44d749"
          }
        ],
        "__v": 0
      },
      "ok": 1,
      "_kareemIgnore": true
    }
    Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961e5211a73e8331b44d74a") } } }, { new: true, upsert: false, remove: false, fields: {} })
    {
      "_id": 1,
      "name": "My Office",
      "__v": 0,
      "branches": [
        {
          "address": "Third address",
          "isPrincipal": false,
          "_id": "5961e5211a73e8331b44d749"
        }
      ]
    }
    Present false
    Mongoose: offices.findOne({}, { fields: {} })
    Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961a56d3ffd3d5e19c61610") } } }, { new: true, passRawResult: true, upsert: false, remove: false, fields: {} })
    {
      "_id": 1,
      "name": "My Office",
      "__v": 0,
      "branches": [
        {
          "address": "Third address",
          "isPrincipal": false,
          "_id": "5961e5211a73e8331b44d749"
        }
      ]
    }
    {
      "lastErrorObject": {
        "updatedExisting": true,
        "n": 1
      },
      "value": {
        "_id": 1,
        "name": "My Office",
        "branches": [
          {
            "address": "Third address",
            "isPrincipal": false,
            "_id": "5961e5211a73e8331b44d749"
          }
        ],
        "__v": 0
      },
      "ok": 1,
      "_kareemIgnore": true
    }
    Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961a56d3ffd3d5e19c61610") } } }, { new: true, upsert: false, remove: false, fields: {} })
    { _id: 1,
      name: 'My Office',
      __v: 0,
      branches:
       [ { address: 'Third address',
           isPrincipal: false,
           _id: 5961e5211a73e8331b44d749 } ] }
    Present true
    Mongoose: offices.update({}, { '$pull': { branches: { _id: ObjectId("5961a56d3ffd3d5e19c61610") } } }, {})
    {
      "n": 1,
      "nModified": 0,
      "opTime": {
        "ts": "6440680872013201413",
        "t": 4
      },
      "electionId": "7fffffff0000000000000004",
      "ok": 1
    }
    Mongoose: offices.findOne({}, { fields: {} })
    Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961a56d3ffd3d5e19c61610") } } }, { new: true, passRawResult: true, upsert: false, remove: false, fields: {} })
    {
      "lastErrorObject": {
        "updatedExisting": true,
        "n": 1
      },
      "value": {
        "_id": 1,
        "name": "My Office",
        "branches": [
          {
            "address": "Third address",
            "isPrincipal": false,
            "_id": "5961e5211a73e8331b44d749"
          }
        ],
        "__v": 0
      },
      "ok": 1,
      "_kareemIgnore": true
    }
    


    1. JavaでmongoDBobjectidを作成する方法

    2. 戻り値Model.create(arr).exec()がマングースで機能していません

    3. マングース:_docはどうしたの?

    4. 別のマシンからコピーされたスナップショット(rdbファイル)からredisデータを回復するにはどうすればよいですか?