мангуст, чтобы определить обновление-upsert выполняет вставку или обновление

Я хочу проверить, работает ли опция "upsert" для обновления. Поэтому я дважды «вставляю» объект в mongodb с одним и тем же ключом. Однако он не отображал вставленное сообщение. Я что-то упустил?

(mongodb: v2.6.3; мангуст: 3.8.15)

Member.findOneAndRemove({user_id: 1},
    function (err, doc) {
        if (!err) onsole.log(doc ? 'deleted' : 'not found');
}); // -> deleted, make sure user_id = 1 doesn't exist

Member.update({user_id: 1}, 
    {$set: {name: "name1"}}, 
    {upsert: true, new: false}, // new : false, so that I can detect original doc is null then know it's a new one.
    function (err, doc) {
    if (!err) {
        console.log(doc ? 'updated' : 'inserted')
    }
}); // -> updated ? But it shoule be inserted, right ?

Member.update({user_id: 1}, 
    {$set: {name: "name2"}}, 
    {upsert: true, new: false},
    function (err, doc) {
    if (!err) {
        console.log(doc ? 'updated' : 'inserted')
    }
}); // -> updated, yes, no problem.

Спасибо за любой намек.

============ ответ =============

Используйте .findOneAndUpdate вместо .update! Кроме того, убедитесь, что опция {upsert: true, new: false}, чтобы второй параметр обратного вызова (doc) мог быть исходным документом на всякий случай.


person nwpie    schedule 03.11.2014    source источник


Ответы (2)


Метод .update() в mongoose принимает три аргумента обратного вызова: err, numAffected , и ответ raw. Используйте «сырой» объект, чтобы увидеть, что произошло:

Member.update({user_id : 1}, 
    {$set : {name:"name1"}}, 
    {upsert : true }, 
    function (err, numAffected, raw) {
    if (!err) {
        console.log(raw)
    }
});

Вы увидите такую ​​структуру:

{ ok: true,
  n: 1,
  updatedExisting: false,
  upserted: [ { index: 0, _id: 5456fc7738209001a6b5e1be } ] }

Таким образом, всегда есть значения n и 'updatedExistingkeys available, where the second is false on upserts and true otherwise.upsertedwill contain the_id` любых новых созданных документов.

Что касается n или «numAffected», в основном это всегда 1, если документ соответствует устаревшим ответам на запрос записи.

Вы можете увидеть новый ответ WriteResult в MongoDB 2.6 и выше, используя форму массовых операций:

var bulk = Member.collection.initializeOrderedBulkOp();
bulk.find({user_id : 1}.upsert().update({$set : {name:"name1"}});
bulk.execute(err,result) {
   console.log( JSON.stringify( result, undefined, 2 ) );
}

Что на первой итерации вы получите примерно так:

{
  "ok": 1,
  "writeErrors": [],
  "writeConcernErrors": [],
  "nInserted": 0,
  "nUpserted": 1,
  "nMatched": 0,
  "nModified": 0,
  "nRemoved": 0,
  "upserted": [
    {
      "index": 0,
      "_id": "5456fff138209001a6b5e1c0"
    }
  ]
}

И второй с такими же параметрами, как этот:

{
  "ok": 1,
  "writeErrors": [],
  "writeConcernErrors": [],
  "nInserted": 0,
  "nUpserted": 0,
  "nMatched": 1,
  "nModified": 0,
  "nRemoved": 0,
  "upserted": []
}

И документ будет отмечен как «измененный» только в том случае, если что-то действительно было изменено.

Так что в любом случае .update() операции не возвращают измененный или исходный документ. Это метод .findOneAndUpdate(), оболочка мангуста вокруг базового .findAndModify(), который выполняет атомарную операцию. Методы .update() обычно предназначены для массовых операций и поэтому не возвращают содержимое документа.

person Neil Lunn    schedule 03.11.2014
comment
Я просто закончил тестировать .findOneAndUpdate, и да, он показал, что я хочу и что вы упомянули. Тем не менее я могу использовать .update () для достижения той же цели. Но .findOneAndUpdate - лучший и простой способ в этом случае. Очень признателен. - person nwpie; 03.11.2014
comment
@Kevin .findOneAndUpdate() на самом деле не говорит вам, добавлено что-то или нет. Особенно с новым набором опций (по умолчанию для мангуста). Вы могли сказать только по "new": false, а оттуда работать в обратном направлении. - person Neil Lunn; 03.11.2014
comment
Я должен был сказать, что используйте .findOneAndUpdate () с опцией {upsert: ture, new: false}. Просто вызов .findOneAndUpdate () все равно запутает ответ. Спасибо за напоминание ! - person nwpie; 03.11.2014
comment
@NeilLunn Можете ли вы объяснить, что вы подразумеваете под работой в обратном направлении? Насколько я могу судить, установка new: false не говорит о том, была ли запись вставлена ​​или обновлена ​​... Фактически, вы имеете в виду, что ищете поле _id в старом документе, и если оно существует, предположите, что запись была обновлена ? - person Soichi Hayashi; 25.02.2016

Что касается редактирования OPs исходного вопроса для использования .findOneAndUpdate, теперь вы также можете передать параметр rawResult: true, который возвращает документ вместе с данными, которые вы обычно получаете при запуске .update, то есть:

{ 
  updatedExisting: true,
  n: 1,
  ok: 1
}

Этого должно быть достаточно, чтобы ответить на исходный вопрос о том, вставили ли вы или добавили.

Я считаю, что этот набор опций обычно желателен для апсертов, использующих .findOneAndUpdate:

  {
    upsert: true,
    new: true,
    runValidators: true,
    setDefaultsOnInsert: true,
    rawResult: true,
  }
person PaulIsLoud    schedule 30.05.2018