mongo db 聚合中 $set 的动态字段路径

时间:2021-02-16 16:42:51

标签: mongodb mongodb-query aggregation-framework

我有包含多语言数据的文档。简化版本如下所示:

  {
    languages: [
      "en",
      "fr"
    ],
    title: {
      en: "Potato Gratin",
      fr: "Gratin de pomme de terre"
    },    
  }

重要的部分是:

  • title 包含形状为 <lang> : <text>
  • 的翻译
  • languages 包含支持的语言列表,第一个是默认语言。
  • 并非所有文档都支持相同的语言

我想做的是查询特定语言的文档,或者

  • 如果语言受支持,请用正确的翻译替换 title 对象
  • 如果语言不是,则用默认翻译替换 title 对象

我-e用法语查询上述文档应该返回{"title": "Gratin de pomme de terre"},如果用中文查询,它应该返回{"title": "Potato Gratin"}

我有一个游乐场设置:https://mongoplayground.net/p/CP0Z20dTpgy。我有它,以便它设置输出应该在的 lang 属性。然后我想要一个看起来像 "$set": {"title": "$title.$lang"} 的阶段,但它抱怨字段路径组件不应以 { 开头{1}},我猜这意味着 mongo 不支持动态字段路径?

知道如何实现这样的目标吗?

一些注意事项:

  • 在实际文档中,我有很多这样的字段,因此使用“$unwind”的解决方案成本很高。
  • 它以语言为键进行结构化的原因是它有助于使用 Mongo Atlas 进行索引。更改结构以包含翻译数组会损害应用的其他部分。

1 个答案:

答案 0 :(得分:2)

您必须使用 $objectToArray 将对象转换为数组,过滤此数组并获取其中的元素 0。然后你就可以将你的价值转化回来。

db.collection.aggregate([
  {
    "$match": {
      "_id": BinData(0, "3BByrilZQ2GTdlXG0nrGXw=="),
      
    },
  },
  {
    "$set": {
      "lang": {
        "$cond": [
          {
            "$in": [
              "zh",
              "$languages"
            ]
          },
          "zh",
          {
            "$first": "$languages"
          }
        ]
      }
    }
  },
  {
    $addFields: {
      title: {
        "$arrayElemAt": [
          {
            "$filter": {
              "input": {
                "$objectToArray": "$title"
              },
              "as": "title",
              "cond": {
                $eq: [
                  "$$title.k",
                  "$lang"
                ]
              }
            }
          },
          0
        ]
      }
    }
  },
  {
    $addFields: {
      title: "$title.v"
    }
  }
])

当然,您必须在代码中的两个地方都将“zh”作为参数传递。

You can test it here