MongoDB 一组具有限制大小的值

MongoDB set of values with a limit size

我正在通过将交易保存到数据库列表来更新交易列表,我不想在列表中有重复的条目所以我使用 $addtoset

这是因为可以多次触发请求,我们希望确保任何更改对数据库都是幂等的。现在唯一的问题是我们只想存储 最新的 20 笔交易

这可以通过 $push $sort $slice 来完成,但我需要确保没有重复的条目。早在 2015 年就曾向 mongo 提出过将此功能添加到 $addtoset 功能的功能请求,但由于 'sets' 未在订单中,他们拒绝了此功能... $sort 函数应该是什么

我想我可以简单地将一个空的推送更新附加到更新对象,但据我了解,每个更新都可能是线程化的,如果 push/slice 在 [=12] 之前触发,则可能导致不希望的编辑=]

现在,这些值是具有以下公式的聚合字符串 timestamp:value 但我可以轻松地将结构更改为对象 {ts:timestamp, value:value}

更新: 当前代码,不确定它是否会按预期工作,因为每个操作可能是独立的

          await historyDB
            .updateOne(
              { trxnId: txid },
              {
                $addToSet: {
                  history: {
                    ts: time,
                    bid: bid.value,
                    txid: trxn.txid,
                  }
                },
                $push: {
                  history: {
                    $each: [{ts:-1}],
                    $sort: { ts: 1 },
                    $slice: -10,
                  },
                },
              },
              { upsert: true },
            ).exec();

您的查询无效,因为您正尝试更新 history 多次,这在简单 更新文档 中是不允许的,并引发错误 Updating the path 'history' would create a conflict at 'history'.

您随后可以使用 聚合管道 .

多次更新 history 字段
await historyDB.updateOne(
  { trxnId: txid},
  [{
    $set: {
      history: {
        $let: {
          vars: {
            historyObj: {
              ts: time,
              bid: bid.value,
              txid: trxn.txid,
            },
            historySafe: { $ifNull: ["$history", []] }
          },
          in: {
            $cond: {
              if: { $in: ["$$historyObj", "$$historySafe"] },
              then: "$history",
              else: { $concatArrays: [ "$$historySafe", ["$$historyObj"] ] }
            }
          }
        }
      }
    },
  },
  {
    $set: {
      history: {
        $function: {
          body: function(entries) {
            entries.sort((a, b) => a.ts - b.ts);
            return entries;
          },
          args: [{ $ifNull: ["$history", []] }],
          lang: "js"
        }
      }
    },
  },
  {
    $set: {
      history: {
        $slice: [ "$history", -10 ]
      }
    }
  }],
  { upsert: true },
).exec()
        

从 MongoDB 6.0 开始,提供排序的第二个 $set 阶段可以替换为 $sortArray 运算符(参见 here)。