对于我的应用程序在MongoDB上执行的每个操作,我都希望拥有文档的旧版本和新版本,以便我可以发出两个版本的事件:
{
type: 'UPDATE',
before: documentBeforeUpdate,
after: documentAfterUpdate
}
我现在这样做的方法是首先对查询发出findOne
,然后对更新进行findOneAndUpdate
,但使用文档的_id
进行查询。因此,如果查询实际上在数据库上引起负载,我不会为此付出两次代价:
async function updateOne(query, updates) {
const oldDocument = await this.model
.findOne(query, null, { lean: true })
.exec();
if (!oldDocument) {
return;
}
const newDocument = await this.model
.findOneAndUpdate({ _id: oldDocument._id }, updates, {
new: true,
lean: true
})
.exec();
// document vanished before it could be updated
if (!newDocument) {
return;
}
await this.emit("UPDATE", {
before: oldDocument,
after: newDocument,
type: "UPDATE"
});
return newDocument;
}
我对updateMany
、delete{One,Many}
、createOne
等都有类似的功能。
现在我的问题是,是否有比这样做更高性能的方法?
上下文
我想做的是分离代码,这些代码会出于查询性能原因对数据库中的数据进行非规范化。假设我有一个应用程序,您可以在餐厅预订餐桌,那么我希望预订位于自己的集合中,但我也希望将每个表的可用性信息缓存在表自己的文档中。因此,我可以查询表的集合以查找特定时间可用的表。
// reservation
{
_id: ObjectId,
table: ObjectId,
from: Date,
to: Date
}
// table
{
_id: ObjectId,
reservations: [
{ _id: ObjectId, from: Date, to: Date },
// ...
]
}
当具有可以侦听文档的创建、更新和删除的事件系统时,我不需要直接从更新保留文档的代码调用更新表的预留属性的代码。这就是我想要实现的架构。
findAndOneUpdate 中有一个选项,称为
返回新文档:布尔值
此选项将告诉 mongodb 返回旧文档,而不是在响应对象中返回更新的文档。
来自 mongo 文档
db.collection.findOneAndUpdate(filter, update, options)
根据筛选器和排序条件更新单个文档。
findOneAndUpdate() 方法具有以下形式:
db.collection.findOneAndUpdate(
<filter>,
<update>,
{
projection: <document>,
sort: <document>,
maxTimeMS: <number>,
upsert: <boolean>,
returnNewDocument: <boolean>,
collation: <document>
}
)
对你的代码不满意: 您的更新对象名为"updates"并传递给findAndUpdateOne应包含字段{returnNewDocument: true}, 然后你需要从findAndUpdateOne方法读取响应,这样你就可以在不运行单独的findOne查询的情况下获取旧文档。
蒙戈手册 - 查找一个和更新 https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndUpdate/