根据另一个子文档更改子文档的引用

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

为了清楚地说明问题,让我从一个例子开始。

假设我们有一系列产品,其中一种产品可以有多个品牌并在不同的商店出售,每个商店可以销售该产品的一个或多个品牌:

    {
      "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 相对容易,但更换商店内的品牌才是真正的问题。

mongodb 中有没有办法更新商店子文档以使用商店的 id 而不是名称?

类似:

db.products.updateMany({}, 
  { 
    $set: { 
      "shops.brands.$" : "$brands[name=$].id" 
    }
  }
)
mongodb mongodb-query
1个回答
0
投票

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

  1. 首先,

    $map
    每个品牌都有基于其索引加1的结构和ID。

    • 如果您希望索引从 0 而不是 1 开始,请删除
      $add: [..., 1]
    • 如果您希望它们作为字符串,请将
      $toString: {}
      放在
      $indexOfArray: {}
      部分周围。
    • 您提到同一品牌出现在多个文档中不需要在不同文档中具有相同的 ID。否则,这将需要完全不同。
  2. 其次,还

    $map
    每个商店,并根据其索引为每个商店品牌嵌套一个
    $map
    。 id 将与上面相同,因为它们是在相同的
    $set
    步骤
    中完成的 - 因此
    "$brands"
    指的是 文档中的当前值,而不是上面设置的值。 (你甚至可以将两者颠倒,结果是一样的。)

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 }
)

蒙戈游乐场

注:

  • 与此一起使用
    updateMany
    ;我仅将
    update
    {multi: true}
    用于 Mongo 游乐场。另外,您可能不需要管道语法数组
    []
    ,因为它只是一个
    $set
    步骤,但如果没有它,它就无法在游乐场上工作。
  • 在使用的示例数据中,我在不同的订单中添加了更多品牌,并且每个商店有多个品牌。
© www.soinside.com 2019 - 2024. All rights reserved.