Spec-Zone.ru › Mongoose

Как использовать findOneAndUpdate() в Mongoose

Функция findOneAndUpdate() в Mongoose имеет широкий спектр применений. Вы должны использовать save() для обновления документов, где это возможно, для лучшей валидации и поддержки средств промежуточного ПО. Однако есть случаи, когда вам необходимо использовать findOneAndUpdate(). В этом руководстве вы узнаете, как использовать findOneAndUpdate(), и поймёте, когда это необходимо.

  • Начало работы
  • Атомарные обновления
  • Upsert
  • Опция rawResult

Начало работы

Как следует из названия, findOneAndUpdate() находит первый документ, соответствующий заданному filter, применяет update, и возвращает документ. По умолчанию findOneAndUpdate() возвращает документ в том виде, в котором он был до применения update.

const Character = mongoose.model('Character', new mongoose.Schema({
  name: String,
  age: Number
}));

await Character.create({ name: 'Jean-Luc Picard' });

const filter = { name: 'Jean-Luc Picard' };
const update = { age: 59 };

// `doc` is the document _before_ `update` was applied
let doc = await Character.findOneAndUpdate(filter, update);
doc.name; // 'Jean-Luc Picard'
doc.age; // undefined

doc = await Character.findOne(filter);
doc.age; // 59

Вы должны установить опцию new в true, чтобы вернуть документ после применения update.

const filter = { name: 'Jean-Luc Picard' };
const update = { age: 59 };

// `doc` is the document _after_ `update` was applied because of
// `new: true`
const doc = await Character.findOneAndUpdate(filter, update, {
  new: true
});
doc.name; // 'Jean-Luc Picard'
doc.age; // 59

findOneAndUpdate() Mongoose немного отличается от findOneAndUpdate() драйвера MongoDB Node.js, потому что он возвращает сам документ, а не объект результата.

В качестве альтернативы опции new, вы также можете использовать опцию returnOriginal. returnOriginal: false эквивалентна new: true. Опция returnOriginal существует для согласованности с findOneAndUpdate() драйвера MongoDB Node.js, которая имеет ту же опцию.

const filter = { name: 'Jean-Luc Picard' };
const update = { age: 59 };

// `doc` is the document _after_ `update` was applied because of
// `returnOriginal: false`
const doc = await Character.findOneAndUpdate(filter, update, {
  returnOriginal: false
});
doc.name; // 'Jean-Luc Picard'
doc.age; // 59

Атомарные обновления

За исключением неиндексированного upsert, findOneAndUpdate() атомарны. Это означает, что вы можете предположить, что документ не изменился между моментом, когда MongoDB находит документ, и моментом, когда он обновляет документ, если только вы не выполняете upsert.

Например, если вы используете save() для обновления документа, документ может измениться в MongoDB между моментом загрузки документа с помощью findOne() и моментом сохранения документа с помощью save(), как показано ниже. Для многих случаев использования проблема гонки save() не актуальна. Но вы можете обойти её с помощью findOneAndUpdate() (или транзакций), если это необходимо.

const filter = { name: 'Jean-Luc Picard' };
const update = { age: 59 };

let doc = await Character.findOne({ name: 'Jean-Luc Picard' });

// Document changed in MongoDB, but not in Mongoose
await Character.updateOne(filter, { name: 'Will Riker' });

// This will update `doc` age to `59`, even though the doc changed.
doc.age = update.age;
await doc.save();

doc = await Character.findOne();
doc.name; // Will Riker
doc.age; // 59

Upsert

Используя опцию upsert, вы можете использовать findOneAndUpdate() как операцию поиска и upsert. Upsert ведёт себя как обычная операция findOneAndUpdate() , если находит документ, соответствующий filter. Однако, если ни один документ не соответствует filter, MongoDB вставит новый документ, объединив filter и update, как показано ниже.

const filter = { name: 'Will Riker' };
const update = { age: 29 };

await Character.countDocuments(filter); // 0

const doc = await Character.findOneAndUpdate(filter, update, {
  new: true,
  upsert: true // Make this update into an upsert
});
doc.name; // Will Riker
doc.age; // 29

Опция `rawResult`

Mongoose по умолчанию преобразует результат findOneAndUpdate(): он возвращает обновлённый документ. Это затрудняет проверку того, был ли документ обновлён или добавлен. Чтобы получить обновлённый документ и проверить, был ли новый документ добавлен MongoDB в рамках одной операции, вы можете установить флаг rawResult, чтобы Mongoose возвращал исходный результат из MongoDB.

const filter = { name: 'Will Riker' };
const update = { age: 29 };

await Character.countDocuments(filter); // 0

const res = await Character.findOneAndUpdate(filter, update, {
  new: true,
  upsert: true,
  rawResult: true // Return the raw result from the MongoDB driver
});

res.value instanceof Character; // true
// The below property will be `false` if MongoDB upserted a new
// document, and `true` if MongoDB updated an existing object.
res.lastErrorObject.updatedExisting; // false

Вот как выглядит объект res из приведённого выше примера:

{ lastErrorObject:
   { n: 1,
     updatedExisting: false,
     upserted: 5e6a9e5ec6e44398ae2ac16a },
  value:
   { _id: 5e6a9e5ec6e44398ae2ac16a,
     name: 'Will Riker',
     __v: 0,
     age: 29 },
  ok: 1 }

© 2010 LearnBoost
Licensed under the MIT License.
https://mongoosejs.com/docs/tutorials/findoneandupdate.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API