如何在 MongoDB 中聚合深度为 3 的文档?
How do you aggregate depth 3 documents in MongoDB?
我还不习惯mongoDB。
我想使用示例数据将它们制作成如下结果。
我想按天求每个字段的总和。
我翻了好几篇文献都找不到答案。
示例数据
[
{
_id: 1,
parentId: 1,
'stats': {
'type': {
'a': {
'n:1': 2,
'n:2': 2
},
'b': {
'n:1': 2,
'n:2': 1,
'n:3': 1
},
'c': {
'n:5': 4
}
}
},
time: ISODate('2021-10-12T05:00:00Z')
},
{
_id: 2,
parentId: 1,
'stats': {
'type': {
'a': {
'n:1': 1,
},
'b': {
'n:1': 2,
'n:2': 3,
'n:3': 4
},
'c': {
'n:4': 2
}
}
},
time: ISODate('2021-10-12T06:00:00Z')
},
{
_id: 3,
parentId: 2,
'stats': {
'type': {
'a': {
'n:1': 3,
},
'b': {
'n:2': 5,
'n:3': 7
},
'c': {
'n:1': 1,
'n:5': 2
}
}
},
time: ISODate('2021-10-13T05:00:00Z')
}
]
结果
[
{ parentId: 1, 'n:1':7, 'n:2':6, 'n:3':5, 'n:4':2, 'n:5':4, year: '2021', month: '10', day:'12'},
{ parentId: 2, 'n:1':4, 'n:2':5, 'n:3':7, 'n:5':2, year: '2021', month: '10', day:'13'},
]
要按parentId、字段、年月日分组。
多个字段计数让我很辛苦。
请帮帮我。
你可以通过几种不同的方式来做到这一点,因为这里的主要需要是重组数据,这样我们就可以正确地$group
它,这是我认为使用各种运算符最简单的方法.
我要提到的是,如果您使用的是版本 5+,则可以简化语法,因为他们添加了新的 $getField 运算符,允许您访问对象上的特定键。然而,由于这个版本仍然很新,我选择不使用它作为我的解决方案:
db.collection.aggregate([
{
$addFields: {
values: {
$reduce: {
input: {
$map: {
input: {
"$objectToArray": "$stats.type"
},
as: "typeObj",
in: {
"$objectToArray": "$$typeObj.v"
},
}
},
initialValue: [],
in: {
"$concatArrays": [
"$$this",
"$$value"
]
}
}
}
}
},
{
$unwind: "$values"
},
{
$group: {
_id: {
parentId: "$parentId",
key: "$values.k"
},
value: {
$sum: "$values.v"
},
time: {
$first: "$time"
}
}
},
{
$group: {
_id: "$_id.parentId",
values: {
$push: {
k: "$_id.key",
v: "$value"
}
},
time: {
$first: "$time"
}
}
},
{
$replaceRoot: {
newRoot: {
"$mergeObjects": [
{
parentId: "$_id"
},
{
"$arrayToObject": "$values"
},
{
year: {
$year: "$time"
}
},
{
month: {
$month: "$time"
}
},
{
day: {
"$dayOfMonth": "$time"
}
},
]
}
}
}
])
我的建议是这个。我使用 { $dateTrunc: { date: "$time", unit: "day" } }
而不是 time: { $first: "$time" }
,它需要 MongoDB 版本 5.0.
db.collection.aggregate([
{ $set: { stats: { $objectToArray: "$stats.type" } } },
{ $set: { stats: { $map: { input: "$stats.v", in: { $objectToArray: "$$this" } } } } },
{
$set: {
stats: {
$reduce: {
input: "$stats",
initialValue: [],
in: { $concatArrays: ["$$value", "$$this"] }
}
}
}
},
{ $unwind: "$stats" },
{
$group: {
_id: {
parentId: "$parentId",
day: { $dateTrunc: { date: "$time", unit: "day" } },
k: "$stats.k"
}, v: { $sum: "$stats.v" }
}
},
{
$group: {
_id: {
parentId: "$_id.parentId",
day: "$_id.day"
},
stats: { $push: { k: "$_id.k", v: "$v" } }
}
},
{ $set: { stats: { $arrayToObject: "$stats" } } },
{ $set: { "_id.day": { $dateToParts: { date: "$_id.day" } } } },
{ $replaceRoot: { newRoot: { $mergeObjects: ["$_id", "$stats"] } } },
{ $set: { year: "$day.year", month: "$day.month", day: "$day.day" } }
])
部分
{ $set: { stats: { $objectToArray: "$stats.type" } } },
{ $set: { stats: { $map: { input: "$stats.v", in: { $objectToArray: "$$this" } } } } },
{
$set: {
stats: {
$reduce: {
input: "$stats",
initialValue: [],
in: { $concatArrays: ["$$value", "$$this"] }
}
}
}
},
等于@TomSlabbaert 回答:
{
$addFields: {
values: {
$reduce: {
input: {
$map: {
input: {
"$objectToArray": "$stats.type"
},
as: "typeObj",
in: {
"$objectToArray": "$$typeObj.v"
},
}
},
initialValue: [],
in: {
"$concatArrays": [
"$$this",
"$$value"
]
}
}
}
}
},
其余只是外观上的差异。
如果你不是运行 MongoDB 5.0 替换
day: { $dateTrunc: { date: "$time", unit: "day" } }
来自
year: { $year: "$time" },
month: { $month: "$time" },
day: { $dayOfMonth: "$time" }
转换回 Date
我还不习惯mongoDB。
我想使用示例数据将它们制作成如下结果。 我想按天求每个字段的总和。
我翻了好几篇文献都找不到答案。
示例数据
[
{
_id: 1,
parentId: 1,
'stats': {
'type': {
'a': {
'n:1': 2,
'n:2': 2
},
'b': {
'n:1': 2,
'n:2': 1,
'n:3': 1
},
'c': {
'n:5': 4
}
}
},
time: ISODate('2021-10-12T05:00:00Z')
},
{
_id: 2,
parentId: 1,
'stats': {
'type': {
'a': {
'n:1': 1,
},
'b': {
'n:1': 2,
'n:2': 3,
'n:3': 4
},
'c': {
'n:4': 2
}
}
},
time: ISODate('2021-10-12T06:00:00Z')
},
{
_id: 3,
parentId: 2,
'stats': {
'type': {
'a': {
'n:1': 3,
},
'b': {
'n:2': 5,
'n:3': 7
},
'c': {
'n:1': 1,
'n:5': 2
}
}
},
time: ISODate('2021-10-13T05:00:00Z')
}
]
结果
[
{ parentId: 1, 'n:1':7, 'n:2':6, 'n:3':5, 'n:4':2, 'n:5':4, year: '2021', month: '10', day:'12'},
{ parentId: 2, 'n:1':4, 'n:2':5, 'n:3':7, 'n:5':2, year: '2021', month: '10', day:'13'},
]
要按parentId、字段、年月日分组。 多个字段计数让我很辛苦。
请帮帮我。
你可以通过几种不同的方式来做到这一点,因为这里的主要需要是重组数据,这样我们就可以正确地$group
它,这是我认为使用各种运算符最简单的方法.
我要提到的是,如果您使用的是版本 5+,则可以简化语法,因为他们添加了新的 $getField 运算符,允许您访问对象上的特定键。然而,由于这个版本仍然很新,我选择不使用它作为我的解决方案:
db.collection.aggregate([
{
$addFields: {
values: {
$reduce: {
input: {
$map: {
input: {
"$objectToArray": "$stats.type"
},
as: "typeObj",
in: {
"$objectToArray": "$$typeObj.v"
},
}
},
initialValue: [],
in: {
"$concatArrays": [
"$$this",
"$$value"
]
}
}
}
}
},
{
$unwind: "$values"
},
{
$group: {
_id: {
parentId: "$parentId",
key: "$values.k"
},
value: {
$sum: "$values.v"
},
time: {
$first: "$time"
}
}
},
{
$group: {
_id: "$_id.parentId",
values: {
$push: {
k: "$_id.key",
v: "$value"
}
},
time: {
$first: "$time"
}
}
},
{
$replaceRoot: {
newRoot: {
"$mergeObjects": [
{
parentId: "$_id"
},
{
"$arrayToObject": "$values"
},
{
year: {
$year: "$time"
}
},
{
month: {
$month: "$time"
}
},
{
day: {
"$dayOfMonth": "$time"
}
},
]
}
}
}
])
我的建议是这个。我使用 { $dateTrunc: { date: "$time", unit: "day" } }
而不是 time: { $first: "$time" }
,它需要 MongoDB 版本 5.0.
db.collection.aggregate([
{ $set: { stats: { $objectToArray: "$stats.type" } } },
{ $set: { stats: { $map: { input: "$stats.v", in: { $objectToArray: "$$this" } } } } },
{
$set: {
stats: {
$reduce: {
input: "$stats",
initialValue: [],
in: { $concatArrays: ["$$value", "$$this"] }
}
}
}
},
{ $unwind: "$stats" },
{
$group: {
_id: {
parentId: "$parentId",
day: { $dateTrunc: { date: "$time", unit: "day" } },
k: "$stats.k"
}, v: { $sum: "$stats.v" }
}
},
{
$group: {
_id: {
parentId: "$_id.parentId",
day: "$_id.day"
},
stats: { $push: { k: "$_id.k", v: "$v" } }
}
},
{ $set: { stats: { $arrayToObject: "$stats" } } },
{ $set: { "_id.day": { $dateToParts: { date: "$_id.day" } } } },
{ $replaceRoot: { newRoot: { $mergeObjects: ["$_id", "$stats"] } } },
{ $set: { year: "$day.year", month: "$day.month", day: "$day.day" } }
])
部分
{ $set: { stats: { $objectToArray: "$stats.type" } } },
{ $set: { stats: { $map: { input: "$stats.v", in: { $objectToArray: "$$this" } } } } },
{
$set: {
stats: {
$reduce: {
input: "$stats",
initialValue: [],
in: { $concatArrays: ["$$value", "$$this"] }
}
}
}
},
等于@TomSlabbaert 回答:
{
$addFields: {
values: {
$reduce: {
input: {
$map: {
input: {
"$objectToArray": "$stats.type"
},
as: "typeObj",
in: {
"$objectToArray": "$$typeObj.v"
},
}
},
initialValue: [],
in: {
"$concatArrays": [
"$$this",
"$$value"
]
}
}
}
}
},
其余只是外观上的差异。
如果你不是运行 MongoDB 5.0 替换
day: { $dateTrunc: { date: "$time", unit: "day" } }
来自
year: { $year: "$time" },
month: { $month: "$time" },
day: { $dayOfMonth: "$time" }
转换回 Date