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

时间:2018-04-17 10:11:35

标签: mongodb mongoose node-mongodb-native

对于我的应用程序在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;
}

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

现在我的问题是,是否有更高效的方式而不是这样做?

上下文

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

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

// table
{
  _id: ObjectId,
  reservations: [
  { _id: ObjectId, from: Date, to: Date },
  // ...
  ]
}

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

1 个答案:

答案 0 :(得分:0)

findAndOneUpdate中有一个名为

的选项
  

returnNewDocument:布尔值

此选项将告诉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查询的情况下获取旧文档。

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