Mongodb 是否可以在包含子文档的数组中按某个值对文档进行分组?

Mongodb 是否可以在包含子文档的数组中按某个值对文档进行分组?,mongodb,Mongodb,我收集了数百万份文件,结构如下: { "_id" : "5c94bdbfcfccf91aa6903254", "source" : "somesourceinfo/6410", "language" : "de-de", "date_created" : "2019-03-22T10:10:58", "data" : [ { "value" : "SALE", "type" : "produ

我收集了数百万份文件,结构如下:

{
    "_id" : "5c94bdbfcfccf91aa6903254",
    "source" : "somesourceinfo/6410",
    "language" : "de-de",
    "date_created" : "2019-03-22T10:10:58",
    "data" : [ 
        {
            "value" : "SALE",
            "type" : "product.category"
        }, 
        {
            "value" : "KOCHEN & BACKEN, Kochen, Bräter / Schmortöpfe",
            "type" : "product.category"
        },
        {
            "value" : "4009209314754",
            "type" : "product.gtin"
        }, 
        {
            "value" : "Fissler",
            "type" : "product.manufacturer"
        }, 
        {
            "value" : "55122631",
            "type" : "product.manufacturer_number"
        }
     ]
}

我需要将具有相同product.gtin的文档合并到单个文档中,其中数据是一个数组,包含匹配文档的所有数据数组的元素

我尝试过聚合框架,但似乎总是在某个地方卡住了。我通常从匹配实际包含product.gtin的文档开始

然后,我尝试按照该值对相应数组元素中的value属性进行分组,并使用$addToSet组合数据数组,但要么无法按照该值进行分组,要么就是找不到正确的表达式来进行分组

我还试图将数组转换为一个对象,并将它们放在文档的根目录中,但后来遇到了问题,因为我们的类型中有一个点,所以我无法再访问属性

我尝试过其他一些方法,但通常在某个时候会遇到问题

我在问自己,用我们这样的数据结构是否真的可以实现这一点

我如何开始的示例:

db.bulk.aggregate(
    [
        {
            $match: { "data.type" : { $eq : "product.gtin" }} 
        }
    ],
    { allowDiskUse : true }
)
下一步是$group,然后使用适当数组元素的值,但我似乎无法访问它。
我见过有人通过$unwind访问数组中的子文档,但这样做之后,我似乎无法真正以良好的方式对示例data.value进行分组,而不按相同的其他值进行分组。

编辑了答案,因为旧的答案包含一个错误:

db.bulk.aggregate(
    [
        {
            $match: { "data.type": { $eq: "product.gtin" } }
        },
        {
            $addFields: {
                gtin: {
                    $reduce: {
                        input: "$data",
                        initialValue: "",
                        in: { $concat: ["$$value", { $cond: { if: { $eq: ["$$this.type", "product.gtin"] }, then: "$$this.value", else: "" } }] }
                    }
                }
            }
        },
        {
            $project: {
                data: {
                    $map: {
                        input: "$data",
                        as: "el",
                        in: { type: "$$el.value", value: "$$el.value", source: "$source" }
                    }
                },
                source: "$source",
                gtin: "$gtin"
            }
        },

        { $group: { _id: "$gtin", data: { $addToSet: "$data" }, source: { $addToSet: "$source" } } },
        {
            $addFields: {
                data: {
                    $reduce: {
                        input: "$data",
                        initialValue: [],
                        in: { $concatArrays: ["$$value", "$$this"] }
                    }
                }
            }
        },
        { $out: "bulk.gtin" }
    ],
    { allowDiskUse: true }
)
我使用$match,因此只选择存在gtin的文档。 我使用$addFIelds将gtin字段添加到文档的根目录中。该字段是通过使用$reduce添加的,当data.type为product.gtin时,它在$data数组上创建,并将data.value的值连接到空字符串的初始值。这样,我就有了一个包含文档gtin的字段,我可以将其用于步骤3。 我使用$project和$map将文档id添加到$data数组中的每个元素。这样就很容易知道每个元素的来源。同样重要的是,通过这种方式,每个$data数组都是不同的。在下一步中使用$addToSet时,将不会将包含完全相同文档的数组添加到一起。但是我们想要重复的,这样我们以后可以数一数。这样,每个$data数组实际上是不同的,因为它包含不同的_id,并且肯定会添加到集合中。 然后,我使用$group按新创建的$gtin字段对文档进行分组。我还通过$addToSet将$data和$source中的值添加到数组中。 我使用addfield覆盖$data字段。在步骤3中,$addInSet没有逐个添加实际的数组元素,而是添加$data中包含的整个数组。 所以我必须从当前在$data中的几个数组中创建一个数组。 我使用reduce实现这一点,它获取$data中包含的元素,并将它们连接在一起。通过这种方式,我还保留了重复的元素,这正是我想要的。 最后,我将输出写入一个新集合