Mongodb聚合将数组对转换为键和值列表

rdlzhqv9  于 2023-02-18  发布在  Go
关注(0)|答案(3)|浏览(292)

尝试将具有键值对的数组压缩为具有键和该键的所有唯一值的对象数组。
我有这样一个结构:

{
  fruits: [
    {fruit: apple, type: gaja},
    {fruit: apple, type: honey-crisp},
    {fruit: apple, type: fuji},
    {fruit: cherry, type: black},
    {fruit: cherry, type: red},
    {fruit: cherry, type: red},
  ]
}

如何将其转换为:

{
  fruits: [
    {fruit: apple, types: [gaja, honey-crisp, fuji]},
    {fruit: cherry, types: [black, red]}
  ]
}

使用mongo聚合,我设法使用$group和$addToSet从我的数据中获得第一个结构。不确定如何将数组Map到具有键和值列表的新对象

ybzsozfc

ybzsozfc1#

下面是另一种方法,使用"$reduce"。注解在聚合管道中。

db.collection.aggregate([
  {
    "$set": {
      // rewrite fruits
      "fruits": {
        "$reduce": {
          "input": "$fruits",
          "initialValue": [],
          "in": {
            "$let": {
              "vars": {
                // get fruit index in $$value : will be -1 if not there
                "idx": {"$indexOfArray": ["$$value.fruit", "$$this.fruit"]}
              },
              "in": {
                "$cond": [
                  // is fruit not in $$value yet
                  {"$eq": ["$$idx", -1]},
                  // new fruit so put in $$value and make "type" an array
                  {
                    "$concatArrays": [
                      "$$value",
                      [{"$mergeObjects": ["$$this", {"type": ["$$this.type"]}]}]
                    ]
                  },
                  // fruit already in $$value, so map $$value with "type" update
                  {
                    "$map": {
                      "input": "$$value",
                      "as": "val",
                      "in": {
                        "$cond": [
                          // is this array element not the right fruit?
                          {"$ne": ["$$val.fruit", "$$this.fruit"]},
                          // nope, leave the element as-is
                          "$$val",
                          // this element needs to be updated
                          {
                            "$mergeObjects": [
                              "$$val",
                              {
                                "type": {
                                  "$cond": [
                                    // is this "type" already in array?
                                    {"$in": ["$$this.type", "$$val.type"]},
                                    // yes, so leave it as-is
                                    "$$val.type",
                                    // this is a new "type", so add it to array
                                    {"$concatArrays": ["$$val.type", ["$$this.type"]]}
                                  ]
                                }
                              }
                            ]
                          }
                        ]
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      }
    }
  }
])

mongoplayground.net上试试。

mgdq6dx1

mgdq6dx12#

也许是这样的:

db.collection.aggregate([
{
  $unwind: "$fruits"
},
{
 $group: {
  _id: "$fruits.fruit",
  type: {
    $push: "$fruits.type"
  }
 }
},
{
 $project: {
  fruit: "$_id",
  type: 1,
  _id: 0
 }
},
{
$group: {
  _id: "",
  fruits: {
    $push: "$$ROOT"
  }
 }
 }
])

解释:
1.展开阵列
1.组以形成类型数组(如果只需要unique,可以使用$push或$addToSet)
1.投影必要的字段
1.将所有文档分组到单个最终文档中
Playground

nkkqxpd9

nkkqxpd93#

这是另一种方法,使用多个"$map""$setUnion"来获得唯一的数组成员。

db.collection.aggregate([
  {
    "$set": {
      // rewrite fruits
      "fruits": {
        "$map": {
          // map over unique fruits
          "input": {"$setUnion": "$fruits.fruit"},
          "as": "theFruit",
          "in": {
            // set fruit
            "fruit": "$$theFruit",
            // "type" are unique elements of fruits.type
            // where fruits.fruit == theFruit
            "type": {
              "$setUnion": {
                "$map": {
                  "input": {
                    "$filter": {
                      "input": "$fruits",
                      "as": "obj",
                      "cond": {"$eq": ["$$obj.fruit", "$$theFruit"]}
                    }
                  },
                  "in": "$$this.type"
                }
              }
            }
          }
        }
      }
    }
  }
])

mongoplayground.net上试试。

相关问题