根据参考图计算子文档列表的最大值

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

我有这样的文档结构:

[
    {
        "country": "UK",
        "shops": [
            {"city": "London", "fruits": ["banana", "apple"]},
            {"city": "Birmingham", "fruits": ["banana", "pineapple"]},
        ],
    },
    {
        "country": "DE",
        "shops": [
            {"city": "Munich", "fruits": ["banana", "strawberry"]},
            {"city": "Berlin", "fruits": ["kiwi", "pineapple"]},
        ],
    },
]

在我的Python脚本中,我有一个字典将每个水果映射到一个类别值:

categories = {
    1: ["apple"],
    2: ["banana", "kiwi"],
    3: ["pineapple", "strawberry"]
}

期望的输出:

现在我想使用 mongo 聚合框架,对于每个文档,根据类别映射从商店子文档中找到的最大值投影出 max_category 。

[
    {
        "country": "UK",
        "shops": [
            {"city": "London", "fruits": ["banana", "apple"]},
            {"city": "Birmingham", "fruits": ["banana", "pineapple"]},
        ],
        "max_category": 3
    },
    {
        "country": "DE",
        "shops": [
            {"city": "Munich", "fruits": ["banana", "apple"]},
            {"city": "Berlin", "fruits": ["kiwi", "apple"]},
        ],
        "max_category": 2
    },
]

感谢您的帮助!

mongodb aggregation-framework
2个回答
1
投票

您的类别字典不适合 mongo,因为 mongo 要求对象具有字符串类型的键。您可以将字典转换为以下形式以便于处理:

[
  {
    category: 1,
    fruits: [
      "apple"
    ]
  },
  {
    category: 2,
    fruits: [
      "banana",
      "kiwi"
    ]
  },
  {
    category: 3,
    fruits: [
      "pineapple",
      "strawberry"
    ]
  }
]

在聚合管道中,通过

$reduce
迭代整理的类别数组,以有条件地更新累加器以获得最大匹配类别。

db.collection.aggregate([
  {
    "$unwind": "$shops"
  },
  {
    "$set": {
      "max_category": {
        "$reduce": {
          "input": [
            {
              category: 1,
              fruits: [
                "apple"
              ]
            },
            {
              category: 2,
              fruits: [
                "banana",
                "kiwi"
              ]
            },
            {
              category: 3,
              fruits: [
                "pineapple",
                "strawberry"
              ]
            }
          ],
          "initialValue": null,
          "in": {
            "$cond": {
              "if": {
                $and: [
                  {
                    $gt: [
                      "$$this.category",
                      "$$value"
                    ]
                  },
                  {
                    $gt: [
                      {
                        $size: {
                          "$setIntersection": [
                            "$$this.fruits",
                            "$shops.fruits"
                          ]
                        }
                      },
                      0
                    ]
                  }
                ]
              },
              "then": "$$this.category",
              "else": "$$value"
            }
          }
        }
      }
    }
  },
  {
    "$group": {
      "_id": "$_id",
      "country": {
        $first: "$country"
      },
      "max_category": {
        $max: "$max_category"
      },
      "shops": {
        "$push": "$shops"
      }
    }
  }
])

蒙戈游乐场


0
投票

一个选项是:

db.collection.aggregate([
  {
    $set: {
      max_category: {
        $max: {
          $reduce: {
            input: "$shops",
            initialValue: 0,
            in: {
              $max: [
                "$$value",
                {
                  $map: {
                    input: "$$this.fruits",
                    as: "f",
                    in: {
                      $toInt: {
                        $getField: {
                          field: "k",
                          input: {
                            $first: {
                              $filter: {
                                input: {
                                  $objectToArray: categories 
                                },
                                as: "val",
                                cond: {
                                  $in: [
                                    "$$f",
                                    "$$val.v"
                                  ]
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
  }
])
© www.soinside.com 2019 - 2024. All rights reserved.