How to Use findOneAndUpdate()
in Mongoose如何在Mongoose中使用findOneAndUpdate()
findOneAndUpdate()
in MongooseThe Mongoose中的findOneAndUpdate()
function in Mongoose has a wide variety of use cases. findOneAndUpdate()
函数有各种各样的用例。You should use 您应该尽可能使用save()
to update documents where possible, for better validation and middleware support. save()
来更新文档,以获得更好的验证和中间件支持。However, there are some cases where you need to use 然而,在某些情况下,您需要使用findOneAndUpdate()
. findOneAndUpdate()
。In this tutorial, you'll see how to use 在本教程中,您将了解如何使用findOneAndUpdate()
, and learn when you need to use it.findOneAndUpdate()
,并了解何时需要使用它。
Getting Started入门
As the name implies, 顾名思义,findOneAndUpdate()
finds the first document that matches a given filter
, applies an update
, and returns the document. By default, findOneAndUpdate()
returns the document as it was before update
was applied.findOneAndUpdate()
查找与给定filter
匹配的第一个文档,应用更新并返回该文档。默认情况下,findOneAndUpdate()
会返回应用更新之前的文档。
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
You should set the 您应该将new
option to true
to return the document after update
was applied.new
选项设置为true
,以便在应用更新后返回文档。
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
Mongoose's Mongoose的findOneAndUpdate()
is slightly different from the MongoDB Node.js driver's findOneAndUpdate()
because it returns the document itself, not a result object.findOneAndUpdate()
与MongoDB Node.js驱动程序的findOneAndUpdate()
略有不同,因为它返回的是文档本身,而不是结果对象。
As an alternative to the 作为new
option, you can also use the returnOriginal
option. new
选项的替代方案,您也可以使用returnOriginal
选项。returnOriginal: false
is equivalent to 相当于new: true
. new: true
。The returnOriginal
option exists for consistency with the the MongoDB Node.js driver's findOneAndUpdate()
, which has the same option.returnOriginal
选项的存在是为了和MongoDB Node.js驱动程序的findOneAndUpdate()
保持一致,后者具有相同的选项。
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
Atomic Updates原子更新
With the exception of an unindexed upsert, 除了未编制索引的upstart之外,findOneAndUpdate()
is atomic. findOneAndUpdate()
是原子的。That means you can assume the document doesn't change between when MongoDB finds the document and when it updates the document, unless you're doing an upsert.这意味着您可以假设文档在MongoDB找到文档和更新文档之间不会发生变化,除非您正在进行upsert。
For example, if you're using 例如,如果您使用save()
to update a document, the document can change in MongoDB in between when you load the document using findOne()
and when you save the document using save()
as show below. save()
更新文档,则在使用findOne()
加载文档和使用save()
保存文档之间,文档可能会在MongoDB中发生更改,如下所示。For many use cases, the 对于许多用例来说,save()
race condition is a non-issue. But you can work around it with findOneAndUpdate()
(or transactions) if you need to.save()
race条件不是问题。但是,如果需要的话,您可以使用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
Using the 使用upsert
option, you can use findOneAndUpdate()
as a find-and- upsert operation. upstart
选项,您可以使用findOneAndUpdate()
作为查找和upsert操作。An upsert behaves like a normal 如果upstart找到与筛选器匹配的文档,那么它的行为与普通的findOneAndUpdate()
if it finds a document that matches filter
. findOneAndUpdate()
类似。But, if no document matches 但是,如果没有文档匹配filter
, MongoDB will insert one by combining filter
and update
as shown below.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
The `rawResult` OptionrawResult
选项
Mongoose transforms the result of Mongoose默认转换findOneAndUpdate()
by default: it returns the updated document. findOneAndUpdate()
的结果:它返回更新后的文档。That makes it difficult to check whether a document was upserted or not. 这使得很难检查文档是否被打乱了。In order to get the updated document and check whether MongoDB upserted a new document in the same operation, you can set the 为了获得更新后的文档并检查MongoDB是否在同一操作中打乱了新文档,您可以设置rawResult
flag to make Mongoose return the raw result from 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
Here's what the 上面例子中的res
object from the above example looks like:res
对象是这样的:
{ lastErrorObject:
{ n: 1,
updatedExisting: false,
upserted: 5e6a9e5ec6e44398ae2ac16a },
value:
{ _id: 5e6a9e5ec6e44398ae2ac16a,
name: 'Will Riker',
__v: 0,
age: 29 },
ok: 1 }