更新时获取文档的旧版本和新版本

des*_*lue 7 mongoose mongodb node-mongodb-native

对于我的应用程序在 MongoDB 上执行的每个操作,我希望拥有文档的旧版本和新版本,以便我可以发出两个版本的事件:

{
  type: 'UPDATE',
  before: documentBeforeUpdate,
  after: documentAfterUpdate
}
Run Code Online (Sandbox Code Playgroud)

我现在执行此操作的方法是首先发出 afindOne查询,然后执行 afindOneAndUpdate更新,但使用文档_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;
}
Run Code Online (Sandbox Code Playgroud)

我有类似的功能updateManydelete{One,Many}等等createOne

现在我的问题是是否有比这样做更高效的方法?

语境

我想做的是解耦那些出于查询性能原因而使数据库中的数据非规范化的代码。假设我有一个可以在餐厅预订桌子的应用程序,那么我希望预订位于自己的集合中,但我也希望将每个桌子的可用性信息缓存在桌子自己的文档中。因此我可以查询表的集合以获取在特定时间可用的表。

// reservation
{
  _id: ObjectId,
  table: ObjectId,
  from: Date,
  to: Date
}

// table
{
  _id: ObjectId,
  reservations: [
  { _id: ObjectId, from: Date, to: Date },
  // ...
  ]
}
Run Code Online (Sandbox Code Playgroud)

当我有一个可以侦听文档的创建、更新和删除的事件系统时,我不需要直接从更新预订文档的代码中调用更新表的预订属性的代码。这就是我想要实现的架构。

小智 -3

findAndOneUpdate 中有一个选项称为

返回新文档:布尔值

此选项将告诉 mongodb 返回旧文档,而不是在响应对象中返回更新的文档。

来自蒙戈文档

db.collection.findOneAndUpdate(filter, update, options)
Run Code Online (Sandbox Code Playgroud)

根据过滤器和排序标准更新单个文档。

findOneAndUpdate() 方法具有以下形式:

db.collection.findOneAndUpdate(
   <filter>,
   <update>,
   {
       projection: <document>,
       sort: <document>,
       maxTimeMS: <number>,
       upsert: <boolean>,
       returnNewDocument: <boolean>,
       collation: <document>
   }
)
Run Code Online (Sandbox Code Playgroud)

注意您的代码:名为“updates”并传递给 findAndUpdateOne 的更新对象应包含字段 {returnNewDocument: true},然后您需要从 findAndUpdateOne 方法读取响应,这样您就可以获取旧文档,而无需运行单独的 findOne 查询。

Mongo手册-findOneAndUpdate https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndUpdate/