mongodb - 是否可以按包含子文档的数组中的某个值对文档进行分组?
问题描述
我有一个包含几百万个文档的集合,其结构如下:
{
"_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 的文档合并到一个文档中,其中 data 是一个数组,其中包含匹配文档的所有数据数组的元素。
我尝试过使用聚合框架,但似乎总是卡在某个地方。我通常首先匹配实际包含“product.gtin”的文档。
然后我尝试按该值(相应数组元素中的 value 属性)进行分组,并使用 $addToSet 组合“数据”-Array,但是按该值分组是不可能的,或者我只是找不到正确的表达式去做吧。
我还尝试将数组转换为对象并将它们放入文档的根目录,但后来我遇到了问题,因为我们的类型中有一个点,所以我不能再访问属性了。
我尝试了其他一些方法,但通常我会在某些时候遇到问题。
我在问自己,这是否真的可以通过像我们这样的数据结构来实现。
我如何开始的示例:
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 我将 document_id 添加到“$data”-Array 中的每个元素。这样就很容易知道每个元素的来源。同样(对我们的用例很重要)这样,每个“$data”-array 都是不同的。在下一步中使用 $addToSet 时,包含完全相同文档的数组不会被添加在一起。但是我们想要重复,以便我们以后可以计算它们。这样每个“$data”数组实际上是不同的,因为它包含不同的_id,并且肯定被添加到集合中。
- 然后我使用 $group 按新创建的“$gtin”字段对文档进行分组。我还通过 $addToSet 将“$data”和“$source”中的值添加到数组中。
- 我使用添加字段来覆盖 $data 字段。在第 3 步中,$addInSet 并没有将实际的数组元素一一添加,而是将整个数组包含在“$data”中。所以我必须从当前位于“$data”中的几个数组中创建一个数组。我为此使用reduce,它获取包含在$data 中的元素并将它们连接在一起。这样我也保留了重复的元素,这是我的意图。
- 最后我将输出写入一个新集合
推荐阅读
- twitter-bootstrap - 如何在文本 value="my text" 中插入 Font Awesome?
- python - Numpy 数组 - 重塑和切片
- python - 从多个csv中提取数据到python中的单个数据框中
- r - 将元素连接到 Rcpp 中 S4 类的插槽
- erlang - Erlang spawn 由于某种原因返回 undef
- excel - =INDEX(PeriodList,MonthNo) 在工作簿中创建 _xlfn.SINGLE 名称
- python - HomeAssistant 取消 AppDaemon 中的回调
- php - PHPUnit错误:找不到类'ClassName'
- c# - 如何在 C# 中添加带字符串的整数并制作类似 Json 的格式
- python - 如何绘制遍历多个键的字典DataFrame?