簡體   English   中英

Toggle 帶有單個查詢的 Mongo 文檔日期屬性

[英]Toggle Mongo Document Date Property With Single Query

只知道 Mongo 中文檔的_id是否有一種直接的方法來編寫一個更新查詢來執行以下操作? 我認為答案是“不”,但我想知道是否有什么東西可以讓這種情況發生。

  1. _id (單個文檔)定位文檔。
  2. 如果文檔中存在readAt字段,請將其刪除
  3. 如果文檔中不存在readAt字段,則將其設置為當前時間

本質上,我想“切換”文檔的“讀取”state(使用日期作為標志)而不實際首先獲取文檔。

目前我正在使用類似的東西:

collection.update(
  {_id: notificationDoc._id},
  notificationDoc.readAt
    ? {$unset: {readAt: true}}
    : {$set: {readAt: new Date()}}
)

效果很好,但需要我首先閱讀該領域。 我並不真正擔心比賽條件或其他任何事情,我只是更願意減少到 DB 的往返行程。


我已經想到了幾種方法來通過兩個具有不同條件的串行更新查詢來做到這一點,但這似乎並不是一種改進。

如果您的MongoDB 版本 >= 4.2 ,那么您可以在更新查詢中指定聚合管道。

db.collection.update(
{ _id: notificationDoc._id },
[
  {
    $set: {
      readAt: {
        $cond: [
          {
            $lte: [
              "$readAt",
              null
            ]
          },
          "$$NOW",
          "$$REMOVE" //(previously null)
        ]
      }
    },
    
  }
])

上面的查詢將readtAt設置為null (如果提供$$REMOVE則將其刪除) if it exists ,則設置為當前日期時間if not exist/null

你可以看到比較是如何工作的

更新(切換)邏輯可以實現如下 - 我將用一個例子來解釋。 考慮一個包含兩個文檔的集合:

{ "_id" : 1, "readAt" : "2020-07-01", "fld" : "Y" }
{ "_id" : 2, "fld" : "N" }

以下聚合刪除了文檔中具有_id: 1readAt字段,並為具有_id: 2的文檔設置了readAt: "2020-07-08"

var NEW_VALUE = "2020-07-08";

db.collection.aggregate([
  { 
      $addFields: { 
          readAt: { 
              $let: {
                  vars: { readAtExists: { $ifNull: [ "$readAt", null ] } },
                  in: { $cond: [ {$eq: [ "$$readAtExists", null ]}, NEW_VALUE, "$$REMOVE"  ] }
              }
          }
      }
  }
])

基於此聚合,您可以通過以下兩種方式之一更新文檔。 一個選項適用於 MongoDB 4.2 或更高版本(使用Update with Aggregation Pipeline ),第二個選項適用於 4.2 之前的版本。


1) 使用聚合管道更新

db.collection.update(
  { _id: 1 },  // { _id: 2 }
  [
    { 
        $set: { 
            readAt: { 
                $let: {
                    vars: { readAtExists: { $ifNull: [ "$readAt", null ] } },
                    in: { $cond: [ {$eq: [ "$$readAtExists", null ]}, NEW_VALUE, "$$REMOVE"  ] }
                }
            }
        }
    }
  ]
)

2)聚合和更新:

db.collection.aggregate( [
  {
      $match: { _id: 1 }  // { _id: 2 }
  },
  { 
      $addFields: { 
          readAt: { 
              $let: {
                  vars: { readAtExists: { $ifNull: [ "$readAt", null ] } },
                  in: { $cond: [ {$eq: [ "$$readAtExists", null ]}, NEW_VALUE, "$$REMOVE"  ] }
              }
          }
      }
  }
] ).forEach( doc => db.collection.replaceOne( { _id: doc._id }, doc ) )

注意:您可以在 MongoDB v4.2 中使用NOW聚合變量來設置聚合中的日期值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM