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

Posted

技术标签:

【中文标题】更新时获取文档的新旧版本【英文标题】:Getting the old and new version of the document when updating it 【发布时间】:2018-09-27 06:13:40 【问题描述】:

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

我对@9​​87654326@、deleteOne,ManycreateOne 等有类似的功能。

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

上下文

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

// reservation

  _id: ObjectId,
  table: ObjectId,
  from: Date,
  to: Date


// table

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

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

【问题讨论】:

【参考方案1】:

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/

【讨论】:

AFAIK OP 希望通过 findOneAndUpdate 接收原始文档和新文档。这个答案表明传递 returnNewDocument: true 作为更新对象的一部分(不是选项 - 所以我们可能会覆盖文档本身中的字段“returnNewDocument”)将返回原始文档以及新文档?这似乎不对,您能详细说明一下吗?

以上是关于更新时获取文档的新旧版本的主要内容,如果未能解决你的问题,请参考以下文章

新旧apache HttpClient 获取httpClient方法

react中的核心概念

(38)ElasticSearch更新文档对并发问题的处理

移动端测试:优化原有功能,改动接口需要兼容新旧版本

根据新旧文件版本或者时间对比,抽取更新文件

如何在使用 couchbase 子文档 api 执行更新时获取 CAS 值?