Mongo 根据多个字段(包括嵌套)的映射追加到标准化字符串字段

Mongo append to standardized string field based on mapping of multiple fields (including nested)

我有一个大型集合,其中包含以下字段:

{
    'class': 'apple'
},
{
    'class': 'appl'
},
{
    'class': 'orange',
    'nested': [
        {'classification': 'app'},
        {'classification': 'A',
        {'classification': 'orang'}
    ]
},
{
    'nested': [
        {'classification': 'O'},
        {'classification': 'unknown'}
    ]
}

我还有一个 Python 字典映射字段值,如:

{
    'class': {
        'apple': 'a',
        'appl': 'a',
        'orange': 'o'
    },
    'nested.classification': {
        'app': 'a',
        'A': 'a',
        'orang': 'o',
        'O': 'o',
        'unknown': 'u'
    }
}

我正在尝试(在 PyMongo 中)更新我的 MongoDB 集合,以便从顶级 class 字段和嵌套 nested.classification 个字段。

在上面,这将产生以下更新:

{
    'class': 'apple'
    'standard': 'a'
},
{
    'class': 'appl'
    'standard': 'a'
},
{
    'class': 'orange',
    'nested': [
        {'classification': 'app'},
        {'classification': 'A',
        {'classification': 'orang'}
    ]
    'standard': 'oaao'
},
{
    'nested': [
        {'classification': 'O'},
        {'classification': 'unknown'}
    ]
    'standard': 'ou'
}

我怎样才能大规模有效地做到这一点?在聚合框架内?

只需 3 个步骤,您就可以得到想要的结果

注意: MongoDB只能迭代数组,所以我们需要把你的字典转成{k:"key", v: "value"}数组(我们可以用$objectToArray , 但不值得)

  1. 我们通过迭代 Python class 字典映射 class 字段
  2. 我们通过迭代 Python nested.classification 字典 nested classification 映射值
  3. 我们将映射值连接成一个值
  4. (可选)如果需要持久化,运行 $merge阶段

免责声明: MongoDB >=4.2 + 我不确定这个解决方案是否适用

db.collection.aggregate([
  {
    "$addFields": {
      standard: {
        $reduce: {
          input: [
            { k: "apple",  v: "a" },
            { k: "appl",   v: "a" },
            { k: "orange", v: "o" }
          ],
          initialValue: "",
          in: {
            $cond: [
              {
                $eq: ["$$this.k", "$class"]
              },
              "$$this.v",
              "$$value"
            ]
          }
        }
      }
    }
  },
  {
    "$addFields": {
      standard: {
        $reduce: {
          input: {
            "$ifNull": [ "$nested", [] ]
          },
          initialValue: [ { v: "$standard" } ],
          in: {
            $concatArrays: [
              "$$value",
              {
                $filter: {
                  input: [
                    { k: "app",     v: "a" },
                    { k: "A",       v: "a" },
                    { k: "orang",   v: "o" },
                    { k: "O",       v: "o" },
                    { k: "unknown", v: "u" }
                  ],
                  as: "nested",
                  cond: {
                    $eq: [ "$$this.classification", "$$nested.k" ]
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  {
    "$addFields": {
      "standard": {
        $reduce: {
          input: "$standard.v",
          initialValue: "",
          in: {
            "$concat": [ "$$value", "$$this" ]
          }
        }
      }
    }
  },
  //Optional - If you need to persist it
  { 
    $merge: {
      into: "collection",
      on: "_id",
      whenMatched: "replace"
    }
  }
])

MongoPlayground