MongoDB 组聚合多个字段可以推送特定的数组字段?

MongoDB Group aggregation multiple field can push specific array field?

下面是我的mongodb文档

{
    "seq": 1,
    "cut": [
        {
            "script":[
                {
                    "type": "a",
                    "text": "a1"
                },
                {
                    "type": "a",
                    "text": "a2"
                },
                {
                    "type": "b",
                    "text": "b1"
                },
                {
                    "type": "c",
                    "text": "c1"
                }
            ]
        },
        {
            "script":[
                {
                    "type": "d",
                    "text": "d1"
                },
                {
                    "type": "a",
                    "text": "a3"
                },
                {
                    "type": "c",
                    "text": "c2"
                },
                {
                    "type": "b",
                    "text": "b2"
                }
            ]
        }
    ]
}

我想使用 type 键使用 $unwind$group 进行文档聚合,如下所示。

{
    "seq": 1,
    "a": ["a1", "a2", "a3"],
    "b": ["b1", "b2"],
    "c": ["c1", "c2"],
    "d": ["d1"]
}

首先,使用$unwind聚合。

$unwind: {
    path: "$cut",
    preserveNullAndEmptyArrays: false
}

并且,它的第一个聚合管道结果是:

{
    "seq": 1,
    "cut": {
        "script":[
            {
                "type": "a",
                "text": "a1"
            },
            {
                "type": "a",
                "text": "a2"
            },
            {
                "type": "b",
                "text": "b1"
            },
            {
                "type": "c",
                "text": "c1"
            }
        ]
        
    }
}

{
    "seq": 1,
    "cut": {
        "script":[
            {
                "type": "d",
                "text": "d1"
            },
            {
                "type": "a",
                "text": "a3"
            },
            {
                "type": "c",
                "text": "c2"
            },
            {
                "type": "b",
                "text": "b2"
            }
        ]
    }
}

接下来,放松cut.script.

$unwind: {
  path: "$cut.script",
  preserveNullAndEmptyArrays: false
}

其结果是:

{
    "seq": 1,
    "cut": {
        "script":{
            "type": "a",
            "text": "a1"
        }
    }
}

{
    "seq": 1,
    "cut": {
        "script":{
            "type": "a",
            "text": "a2"
        }
    }
}

and more 6 document..

最后,我希望此结果与 seq 字段分组。所以我使用 $push 表达式。

{
    _id: "$seq",
    "a": {
        $push: "$cut.script.text"
    },
    "b": {
        $push: "$cut.script.text"
    },
    "c": {
        $push: "$cut.script.text"
    },
    "d": {
        $push: "$cut.script.text"
    }
}

但它 $push 表达式是推送脚本的所有项目。 $push 如何使用条件推送特定字段(例如;“type”等于“a”的“text”值)值?

你可以尝试在聚合中使用 $cond

      {
        $group: {
          _id: "$seq",
          "a": {
            $push: {
              $cond: { 
                if: { $eq: [ "$cut.script.type", "a" ] }, 
                then: ["$cut.script.text"] ,
                else: null,
              }
            }
          }
        }
      }

试试这个 (Mongoplayground Link):

db.collection.aggregate({
  $unwind: {
    path: "$cut",
    preserveNullAndEmptyArrays: false
  }
},
{
  $unwind: {
    path: "$cut.script"
  }
},
{
  $group: {
    "_id": "$seq",
    "a": {
      $push: {
        $cond: {
          if: {
            $eq: [
              "$cut.script.type",
              "a"
            ]
          },
          then: "$cut.script.text",
          else: "$$REMOVE"
        }
      }
    },
    "b": {
      $push: {
        $cond: {
          if: {
            $eq: [
              "$cut.script.type",
              "b"
            ]
          },
          then: "$cut.script.text",
          else: "$$REMOVE"
        }
      }
    },
    "c": {
      $push: {
        $cond: {
          if: {
            $eq: [
              "$cut.script.type",
              "c"
            ]
          },
          then: "$cut.script.text",
          else: "$$REMOVE"
        }
      }
    },
    "d": {
      $push: {
        $cond: {
          if: {
            $eq: [
              "$cut.script.type",
              "d"
            ]
          },
          then: "$cut.script.text",
          else: "$$REMOVE"
        }
      }
    }
  }
})

我更喜欢 dynamic/generic 解决方案:

db.collection.aggregate([
   { $unwind: "$cut" },
   { $unwind: "$cut.script" },
   {
      $group: {
         _id: { seq: "$seq", type: "$cut.script.type" },
         text: { $push: "$cut.script.text" }
      }
   },
   { $sort: { "_id.type": 1 } },
   {
      $group: {
         _id: "$_id.seq",
         data: { $push: { k: "$_id.type", v: "$text" } }
      }
   },
   { $replaceWith: { $mergeObjects: [{ seq: "$_id" }, { $arrayToObject: "$data" }] } }
])

Mongo Playground