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

FindAndUpdate Как да проверите дали документът наистина е актуализиран

Единственият истински надежден начин да видите дали е приложена актуализация за нещо като $pull е основно да проверите върнатия документ и да видите дали данните, които сте възнамерявали да $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(), „Надежден е“

Другият случай, който трябва да разгледате тук, поставя под въпрос дали така или иначе „наистина се нуждаете“ от върнатите модифицирани данни. Тъй като .update() метод, ще върне надеждно резултат, който ви казва дали нещо действително е било променено:

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

Където резултат тук ще изглежда така:

{
  "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, който има надеждни резултати, показващи действителни модификации. Същото би се отнасяло за нещо като $set което всъщност не промени стойността, тъй като предоставената стойност беше равна на вече съществуващата в документа.

findAndModify Lies!

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

Проблемът е (както и необходимостта от повече работа с 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
}

Така че дори след цялата тази работа за извличане на „третия“ аргумент от отговора за обратно извикване, все още не ни беше казана правилната информация за актуализацията.

Заключение

Така че, ако искате "надеждно" да направите това с една заявка ( и вие не можете правете това надеждно с множество заявки, тъй като документът може да се промени между! ) тогава вашите две възможности са:

  1. Проверете върнатия документ, за да видите дали данните, които искате да премахнете, все още са там.

  2. Забравете връщането на документ и се доверете на .update() винаги ти казва "истината";)

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

Малко малка обява

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

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. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Полетата за резултати от Mongoose/MongoDB изглеждат недефинирани в Javascript

  2. Запитване на MongoDB GridFS?

  3. Как да използвате Spring за свързване с MongoDB, което изисква удостоверяване

  4. Връщане на масив от поддокументи чрез Meteor / Mongo

  5. вземете запис с поне един асоцииран обект