为了把问题弄清楚,让我先举一个例子.

假设我们有一个产品集合,其中一个产品可以有多个品牌,并在不同的store 出售,每个store 可以出售该产品的一个或多个品牌:

    {
      "name": "Pen",
      "shops": [
        {
          "name": "Target",
          "brands": [
            "BIC"
          ]
        },
        {
          "name": "Walmart",
          "brands": [
            "Parker"
          ]
        }
      ],
      "brands": [
        {
          "name": "BIC"
        },
        {
          "name": "Parker"
        }
      ]
    }

然而,由于不可预见的情况,我们不能再使用品牌名称作为参考,而是应该使用另一个标识符. 然而,我们必须更新所有现有的集合文件,以使其具有如下所示:

     {
          "name": "Pen",
          "shops": [
            {
              "name": "Target",
              "brands": [
                "1"
              ]
            },
            {
              "name": "Walmart",
              "brands": [
                "2"
              ]
            }
          ],
          "brands": [
            {
              "id": "1"
              "name": "BIC"
            },
            {
              "id": "2"
              "name": "Parker"
            }
          ]
        }

在品牌上添加ID相对容易,但更换store 内的品牌才是真正的问题.

在mongodb中有没有一种方法来更新shops子文档以使用shops的id而不是名称?

比如:

db.products.updateMany({}, 
  { 
    $set: { 
      "shops.brands.$" : "$brands[name=$].id" 
    }
  }
)

推荐答案

所以这里有一个更新命令,它可以实现你想要的.

  1. 首先,每个品牌$map个,其 struct 和ID基于其索引加1.

    • 如果希望索引从0开始而不是1,请删除$add: [..., 1].
    • 如果你想把它们作为字符串,在$indexOfArray: {}部分周围加上$toString: {}.
    • 您提到same brand occurring in multiple documents不需要在不同的文档中具有相同的ID.否则,这将需要完全不同.
  2. 第二,每个store 也$map和嵌套$map每个store 品牌的基础上其指数.id将与上面相同,因为它们是在same 102 step中完成的—所以"$brands"指的是current value in the document,而不是上面设置的.(你甚至可以将两者颠倒,结果将是一样的.

db.products.update({},
[
  {
    $set: {
      // create new brandIDs based on index
      "brands": {
        $map: {
          input: "$brands",
          as: "brand",
          in: {
            "name": "$$brand.name",
            "id": {
              $add: [
                { $indexOfArray: ["$brands", "$$brand"] },
                1
              ]
            }
          }
        }
      },
      // also create shop-brandIDs based on their index
      "shops": {
        $map: {
          input: "$shops",
          as: "shop",
          in: {
            "name": "$$shop.name",
            "brands": {
              $map: {
                input: "$$shop.brands",
                as: "shop_brand",
                in: {
                  $add: [
                    { $indexOfArray: ["$brands", { "name": "$$shop_brand" }] },
                    1
                  ]
                }
              }
            }
          }
        }
      }
    }
  }
],
{ multi: true }
)

Mongo Playground

注:

  • 使用updateMany与这个;我使用update{multi: true}只用于Mongoplayground .此外,您可能不需要流水线数组语法[],因为它只是一个$set步骤.但在操场上没有它就不行了.
  • 在使用的示例数据中,我添加了更多品牌,每个store 有多个品牌.&

Mongodb相关问答推荐

在MongoDB中使用explain()和查询时缺少winningPlan''''

如何将数组$拉到对象数组下

MongoDB MQL,将列表一分为二,仅获取唯一值

在服务器上部署后端时判断??=默认判断

执行聚合以消除重复并获得唯一计数

构造函数的参数 0 需要错误类型的 bean

Mongodb聚合查找连接两个对象字段的集合数组匹配对象索引字段的总和

看起来当我执行 fs.writeFile() 时,更改的文件会重新启动 nodemon.怎么让它不重启?

使用 EventSourcing(NodeJS、MongoDB、JSON)跨多个偶尔连接的客户端同步数据

从 mongodb 中的副本配置重新开始

具有多个字段的mongodb文本搜索

如何使用原子操作在一个文档中切换布尔字段?

将 JSON 与 MongoDB 一起使用?

是否有适用于 Linux 的 MongoDB GUI 桌面应用程序?

MongoDB 3 Java判断集合是否存在

MongoDB中超过2GB的数据库

MongoDB 日志(log)文件和 oplog 有何不同?

$orderby 和 Sort 之间的 MongoDB 区别

Java + MongoDB:更新文档中的多个字段

使用 Mongoose ORM 的杀手锏是什么?