【问题标题】:MongoDB return both "before" and "after" documentMongoDB 返回“之前”和“之后”文档
【发布时间】:2019-09-20 03:58:46
【问题描述】:

当我更新MongoDB 中的文档时,我可以指定是要返回原始文档还是新更新的文档。例如,使用PyMongo,我可以调用:

user = db['users'].find_one_and_update(
    {'email': email},
    {'$set': {'last_login': time.time()}},
    return_document=ReturnDocument.AFTER
)

我也可以使用ReturnDocument.BEFORE

有没有办法让 single mongo 查询同时返回原始值和新值?

【问题讨论】:

  • 您可以避免第二次查询来获取最新的。返回 BEFORE 文档并保留使用 variables 更新的属性。使用这些变量来修改 BEFORE 文档以获取 AFTER 文档。但是,这仅适用于单线程应用程序。
  • 如前所述,只需返回“BEFORE”修改状态,然后应用您的“更改”即可为您提供“修改后”。即使使用$inc 之类的东西,该文档也被操作有效地“锁定以进行更新”,因此除了您的“更新”之外,没有任何东西可以修改该“之前”状态。
  • @mintekhab 操作所固有的findAndModify 命令的实际工作方式对“单线程”没有任何限制。没有其他东西可以修改文档,因此“之后”状态会因“之前”和“那个更新”中所做的修改的组合而不同。
  • @poundifdef,如何更新问题以在更新中使用$currentDate?我认为这会更清楚地说明问题。

标签: mongodb pymongo


【解决方案1】:

MongoDB 不支持你做你想做的事,可悲的是......

returnNewDocument |布尔值 |可选的。当为真时,返回更新的 文件而不是原始文件。默认为 false。

db.collection.findOneAndUpdate(
   <filter>,
   <update document or aggregation pipeline>, // Changed in MongoDB 4.2
   {
     projection: <document>,
     sort: <document>,
     maxTimeMS: <number>,
     upsert: <boolean>,
     returnNewDocument: <boolean>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ]
   }
)

来自db.collection.findOneAndUpdate()


您可以首先使用findOneAndUpdate()returnNewDocument = false,并获取旧值,然后执行常规findOne(),但都在事务块中,因此即使对db 有两次调用,它看起来像从外部进行一次操作。

PyMongo 会是这样的;

users = client.db.users
with client.start_session() as session:
    with session.start_transaction():
        oldUser = users.find_one_and_update(
            {'email': email},
            {'$set': {'last_login': time.time()}},
            session=session
        )
        newUser = users.find_one({'email': email}, session=session)

return_document 默认为ReturnDocument.BEFORE,因此在find_one_and_update() 中没有明确设置

来自Transactionsclient_session(PyMongo)

【讨论】:

    【解决方案2】:

    本机不支持此功能。但是,如果您真的想在数据库端执行这两个命令并返回一个响应 - 那么您可以编写自定义 Javascript 函数(使用 map_reduce,因为不推荐使用 eval)。

    By this link 你可以找到一些如何使用 pymongo 编写自定义 Javascript 函数的示例。

    【讨论】:

      【解决方案3】:

      对于类似的用例,我采取了将文档的“历史”修订写入单独数据库的策略,并在主数据库中维护参考记录的键值。

      这可能会或可能不会带来很多后端影响,但如果不是,它是一种在数据库中处理记录版本控制的直接方法,而数据库并非专为它设计。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-20
        • 1970-01-01
        • 2018-06-02
        • 2019-05-13
        • 2014-11-05
        • 1970-01-01
        • 1970-01-01
        • 2012-11-16
        相关资源
        最近更新 更多