使用新值更新 MongoDB 中的许多文档

问题描述 投票:0回答:1

我的服务器上有 mongodb 版本 3.6。我的服务器源在nodeJS

我有一些这样的文件:

{"title": "test1", sort: 1, parent: 1},
{"title": "test2", sort: 7, parent: 1},
{"title": "test3", sort: 5, parent: 1},

{"title": "test4", sort: 1, parent: 2},
{"title": "test5", sort: 7, parent: 2},
{"title": "test6", sort: 5, parent: 2}

现在我想更新一组文档(例如带有

parent=1
的文档),并按照
previous value plus 10
以数字 1 开头的模式设置该组的排序字段值与新值。

所以我想要下面的结果:

{"title": "test1", sort: 1, parent: 1},
{"title": "test2", sort: 21, parent: 1},
{"title": "test3", sort: 11, parent: 1},

{"title": "test4", sort: 1, parent: 2},
{"title": "test5", sort: 7, parent: 2},
{"title": "test6", sort: 5, parent: 2}

执行此操作的最佳方式和最佳性能是什么?

mongodb mongoose
1个回答
0
投票

仅使用 Mongo 3.6 中可用的操作:

由于您一次只想更新一个父级,因此最后一个阶段是

$merge
。并且文档仅包含原始
_id
和新
sort
的字段。

db.collection.aggregate([
  {
    // match on the parent you want
    $match: { "parent": 1 }
  },
  {
    // sort the docs under that parent
    $sort: { "sort": 1 }
  },
  {
    // create a group for that one parent which is
    // currently all docs due to first $match stage
    $group: {
      _id: null,
      docs: {
        // docs will be already sorted in this array
        $push: "$$ROOT"
      }
    }
  },
  {
    // set each doc `sort` field to the value it should be
    // based on its index in docs
    $set: {
      docs: {
        $map: {
          input: "$docs",
          in: {
            "_id": "$$this._id",
            "sort": {
              $add: [
                1,
                {
                  $multiply: [
                    { $indexOfArray: ["$docs", "$$this"] },
                    10
                  ]
                }
              ]
            }
          }
        }
      }
    }
  },
  { $unwind: "$docs" },
  { $replaceRoot: { newRoot: "$docs" } },
  { $merge: "collection" }
])

蒙戈游乐场

如果您想查看完整的结果文档是什么,请参阅这个类似的管道。主要区别是

$map
阶段的
$set
部分,其中包括所有文档字段。您还可以添加最后一个
{ $merge: "collection" }
阶段来按原样使用此管道。但既然您询问了性能,那么合并应该只包含更新的字段,而不是完整的文档。

顺便说一句,为了性能,最好将更新应用于所有文档,而不必每次都设置父文档。即更新

每个父组的所有文档
sort 值。


如果您使用的是 Mongo 5.0+ 并且

$setWindowFields
可用,那么这适用:

与您的相关的先前问题相比,此答案所需的更改相当小,我的答案

  1. 使用 $rank

    $setWindowFields
     功能提供排名 1、2、3 等,这将基于现有 
    sort
    值。

    • partitionBy
      添加
      parent
      ,以便每个分区(组)由父分区分隔。
  2. 最终的新排序将是

    (rank - 1) x 10 + 1

    • 针对每个文档每组进行计算
  3. 使用

    $out
    操作将所有更新的文档写回到同一个集合中。

唯一的变化是在

partitionBy: "$parent"
中添加了
$setWindowFields

db.collection.aggregate([
  {
    $setWindowFields: {
      partitionBy: "$parent",
      sortBy: { sort: 1 },
      output: {
        sort: { $rank: {} }
      }
    }
  },
  {
    $set: {
      sort: {
        $add: [
          1,
          {
            $multiply: [
              { $subtract: ["$sort", 1] },
              10
            ]
          }
        ]
      }
    }
  },
  { $out: "collection" }
])

蒙戈游乐场

© www.soinside.com 2019 - 2024. All rights reserved.