数据库中的文件格式如下
{
product: 'product1',
state: 'state1',
nondnd: [1, 2, 3],
dnd: [4, 5],
land: [],
emails: ['a', 'b', 'c']
},
{
product: 'product1',
state: 'state1',
nondnd: [9, 8, 2],
dnd: [10, 7, 11],
land: [2, 4, 6, 8],
emails: ['d']
},
{
product: 'product1',
state: 'state2',
nondnd: [9, 8, 2],
dnd: [10, 7, 11],
land: [1, 3],
emails: ['e', 'g']
}
我需要在产品和产品的基础上对上述文件进行分组。陈述并以下面的格式获取它们
{
_id: {
product: 'product1',
state: 'state1'
},
nondnd: [1, 2, 3, 9, 8, 2],
dnd: [4, 5, 10, 7, 11],
land: [2, 4, 6, 8],
emails: ['a', 'b', 'c', 'd']
},
{
_id:{
product: 'product1',
state: 'state2'
},
nondnd: [2, 5, 8],
dnd: [1, 4, 7],
land: [1, 3],
emails: ['e', 'g']
}
我试图单独解开它们并将它们分组。但当我解开它们时,相同的数字正在重复。请帮帮我
答案 0 :(得分:2)
根据您的可用版本和实用性,您可以只应用$reduce
和$concatArrays
,以便在分组文档中“加入”生成的“数组数组”:
db.getCollection('stuff').aggregate([
{ "$group": {
"_id": {
"product": "$product", "state": "$state"
},
"nondnd": { "$push": "$nondnd" },
"dnd": { "$push": "$dnd" },
"land": { "$push": "$land" },
"emails": { "$push": "$emails" }
}},
{ "$addFields": {
"nondnd": {
"$reduce": {
"input": "$nondnd",
"initialValue": [],
"in": { "$concatArrays": [ "$$value", "$$this" ] }
}
},
"dnd": {
"$reduce": {
"input": "$dnd",
"initialValue": [],
"in": { "$concatArrays": [ "$$value", "$$this" ] }
}
},
"land": {
"$reduce": {
"input": "$land",
"initialValue": [],
"in": { "$concatArrays": [ "$$value", "$$this" ] }
}
},
"emails": {
"$reduce": {
"input": "$emails",
"initialValue": [],
"in": { "$concatArrays": [ "$$value", "$$this" ] }
}
}
}}
])
甚至是“超现代”,你真的不喜欢重复自己(但你可能应该生成管道阶段):
db.getCollection('stuff').aggregate([
{ "$project": {
"product": 1,
"state": 1,
"data": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"cond": { "$in": [ "$$this.k", ["nondnd","dnd","land","emails"] ] }
}
}
}},
{ "$unwind": "$data" },
{ "$unwind": "$data.v" },
{ "$group": {
"_id": {
"product": "$product",
"state": "$state",
"k": "$data.k"
},
"v": { "$push": "$data.v" }
}},
{ "$group": {
"_id": {
"product": "$_id.product",
"state": "$_id.state"
},
"data": { "$push": { "k": "$_id.k", "v": "$v" } }
}},
{ "$replaceRoot": {
"newRoot": {
"$arrayToObject": {
"$concatArrays": [
[{ "k": "_id", "v": "$_id" }],
{ "$map": {
"input": ["nondnd","dnd","land","emails"],
"in": {
"$cond": {
"if": { "$ne": [{ "$indexOfArray": [ "$data.k", "$$this" ] },-1] },
"then": {
"$arrayElemAt": [
"$data",
{ "$indexOfArray": [ "$data.k", "$$this" ] }
]
},
"else": { "k": "$$this", "v": [] }
}
}
}}
]
}
}
}}
])
或者您可以在源处交替连接数组并将它们映射到类型。然后在分组后重建:
db.getCollection('stuff').aggregate([
{ "$project": {
"product": 1,
"state": 1,
"combined": {
"$concatArrays": [
{ "$map": {
"input": "$nondnd",
"in": { "t": "nondnd", "v": "$$this" }
}},
{ "$map": {
"input": "$dnd",
"in": { "t": "dnd", "v": "$$this" }
}},
{ "$map": {
"input": "$land",
"in": { "t": "land", "v": "$$this" }
}},
{ "$map": {
"input": "$emails",
"in": { "t": "emails", "v": "$$this" }
}}
]
}
}},
{ "$unwind": "$combined" },
{ "$group": {
"_id": {
"product": "$product", "state": "$state"
},
"combined": { "$push": "$combined" }
}},
{ "$project": {
"nondnd": {
"$map": {
"input": {
"$filter": {
"input": "$combined",
"cond": { "$eq": [ "$$this.t", "nondnd" ] }
}
},
"in": "$$this.v"
}
},
"dnd": {
"$map": {
"input": {
"$filter": {
"input": "$combined",
"cond": { "$eq": [ "$$this.t", "dnd" ] }
}
},
"in": "$$this.v"
}
},
"land": {
"$map": {
"input": {
"$filter": {
"input": "$combined",
"cond": { "$eq": [ "$$this.t", "land" ] }
}
},
"in": "$$this.v"
}
},
"emails": {
"$map": {
"input": {
"$filter": {
"input": "$combined",
"cond": { "$eq": [ "$$this.t", "emails" ] }
}
},
"in": "$$this.v"
}
}
}}
])
在构建和解构单个连接数组的内容时,很大程度上取决于$map
和$filter
,这对于$unwind
来说当然是完全正确的。
同样的结果来自每个案例:
/* 1 */
{
"_id" : {
"product" : "product1",
"state" : "state2"
},
"nondnd" : [
9.0,
8.0,
2.0
],
"dnd" : [
10.0,
7.0,
11.0
],
"land" : [
1.0,
3.0
],
"emails" : [
"e",
"g"
]
}
/* 2 */
{
"_id" : {
"product" : "product1",
"state" : "state1"
},
"nondnd" : [
1.0,
2.0,
3.0,
9.0,
8.0,
2.0
],
"dnd" : [
4.0,
5.0,
10.0,
7.0,
11.0
],
"land" : [
2.0,
4.0,
6.0,
8.0
],
"emails" : [
"a",
"b",
"c",
"d"
]
}