MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

FindAndUpdate Cách kiểm tra xem tài liệu đã thực sự được cập nhật chưa

Cách duy nhất thực sự đáng tin cậy để xem liệu bản cập nhật có được áp dụng cho một thứ gì đó như $ pull về cơ bản là kiểm tra tài liệu được trả lại và xem liệu dữ liệu bạn có ý định $ pull vẫn ở đó hay không.

Đó là đối với bất kỳ "findAndUpdate" nhiều hành động khác nhau và có một lý do hợp lệ cho điều đó cũng như nó cũng là trường hợp đơn giản .update () sẽ thực sự "đáng tin cậy" cho bạn biết liệu sửa đổi có thực sự được thực hiện hay không.

Để xem qua các trường hợp:

Kiểm tra Nội dung Trả lại

Về cơ bản, điều này liên quan đến việc xem xét mảng trong tài liệu trả về để xem liệu những gì chúng tôi yêu cầu xóa có thực sự ở đó hay không:

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

Chúng tôi sử dụng .toHexString () để so sánh giá trị thực từ một ObjectId vì JavaScript không thực hiện "bình đẳng" với "Đối tượng". Bạn sẽ kiểm tra cả "trái" và "phải" nếu cung cấp thứ gì đó đã được "truyền" vào ObjectId nhưng trong trường hợp này, chúng tôi biết đầu vào khác là "chuỗi".

Chỉ cần sử dụng .update (), "Đáng tin cậy"

Trường hợp khác cần xem xét ở đây là câu hỏi liệu bạn có "thực sự cần" dữ liệu đã sửa đổi trả về hay không. Vì .update () phương thức, sẽ trả về một kết quả một cách đáng tin cậy cho bạn biết liệu có gì thực sự đã được sửa đổi hay không:

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

Trong đó kết quả ở đây sẽ giống như sau:

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

Và trong đó nModified là một chỉ báo "đúng" về việc một thứ gì đó "thực sự được cập nhật" hay không. Do đó, nếu nó là 1 sau đó là $ pull thực sự có ảnh hưởng, nhưng khi 0 không có gì thực sự bị xóa khỏi mảng và không có gì được sửa đổi.

Điều này là do phương pháp thực sự sử dụng API đã cập nhật, API này có kết quả đáng tin cậy cho biết các sửa đổi thực tế. Điều tương tự cũng sẽ áp dụng cho một cái gì đó như $ set mà không thực sự thay đổi giá trị vì giá trị được cung cấp bằng với giá trị đã tồn tại trong tài liệu.

findAndModify Lies!

Trường hợp khác ở đây bạn có thể nghĩ đến khi xem kỹ tài liệu là kiểm tra thực sự "kết quả thô" và xem liệu tài liệu có bị sửa đổi hay không. Thực sự có một chỉ báo trong đặc điểm kỹ thuật cho điều này.

Vấn đề là (cũng như cần phải làm việc nhiều hơn với Promises) rằng kết quả không thực sự trung thực:

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

Vấn đề ở đây là ngay cả khi chúng ta "biết" điều này không nên sửa đổi, phản hồi lại nói khác:

{
  "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
}

Vì vậy, ngay cả sau tất cả công việc để lấy đối số "thứ ba" ra khỏi phản hồi gọi lại, chúng tôi vẫn không nhận được thông tin chính xác về bản cập nhật.

Kết luận

Vì vậy, nếu bạn muốn thực hiện việc này một cách "đáng tin cậy" với một yêu cầu duy nhất (và bạn không thể làm điều đó một cách đáng tin cậy với nhiều yêu cầu vì tài liệu có thể thay đổi ở giữa! ) thì hai lựa chọn của bạn là:

  1. Kiểm tra tài liệu được trả lại để xem liệu dữ liệu bạn muốn xóa có còn ở đó không.

  2. Quên trả lại tài liệu và tin tưởng rằng .update () luôn nói cho bạn biết "sự thật";)

Bạn sử dụng cách nào trong số này tùy thuộc vào kiểu sử dụng ứng dụng, nhưng đó là hai cách khác nhau để trả về kết quả "đáng tin cậy".

Bit của một danh sách

Vì vậy, chỉ để chắc chắn, đây là danh sách bao gồm tất cả các ví dụ và chứng minh những gì chúng thực sự trả lại:

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

Và sản lượng nó tạo ra:

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. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Mongo có thể trả lại các tài liệu có các trường trống / thiếu ở cuối theo thứ tự asc không?

  2. Sử dụng Meteor tìm nạp hoặc tìm trong các chức năng của trình trợ giúp mẫu?

  3. Cập nhật từ điển trong Mongodb

  4. Cách trích xuất dấu thời gian từ mongodb objectid trong postgres

  5. Sự khác biệt giữa bây giờ và một ngày nhất định