如何使用$mergeObjects合并现有组对应的数组?
How to use $mergeObjects to merge arrays corresponding to existing groups?
我正在尝试合并聚合管道中的两个数组。执行 $facet 后,我的 MongoDB 文档具有以下格式:
{
"final": [
{
"key": "TP-1",
"status_map": [
{ "status": "Closed", "final": [ "a", "b"]},
{ "status": "Done", "final": ["c","d" ] }
]
},
{
"key": "TP-2",
"status_map": [
{ "status": "Closed", "final": [ "x","y"] }
]
}
],
"start": [
{
"key": "TP-1",
"status_map": [
{ "status": "Closed", "start": [ "h"]},
{ "status": "Done", "start": ["a"]}
]
},
{
"key": "TP-2",
"status_map": [{ "status": "Done", "start": ["l","m"]}
]
}
]
}
预期输出:
我需要合并对应两组的final
和start
数组:
- 基于
key
然后
- 基于
status
{
"data": [
{
"key": "TP-1",
"status_map": [
{ "status": "Closed","final": ["a","b"],"start":["h"]},
{ "status": "Done","final": ["c","d"],"start":["a"]}
]
},
{
"key": "TP-2",
"status_map": [
{ "status": "Closed", "final":[ "x","y"],"start": []},
{ "status": "Done", "final": [ ],"start": [ "l","m"]}
]
}
]
}
如何实现这个用例?
在没有任何假设的情况下(例如,两个键总是出现),我的策略是连接两个数组,展开并最终按键分组。
db.collection.aggregate([
{
$project: {
concat: {
$concatArrays: [
"$final",
"$start"
]
}
}
},
{
$unwind: "$concat"
},
{
$unwind: "$concat.status_map"
},
{
$group: {
_id: {
k: "$concat.key",
status: "$concat.status_map.status"
},
final: {
$push: "$concat.status_map.final"
},
start: {
$push: "$concat.status_map.start"
}
}
},
{
$group: {
_id: "$_id.k",
status_map: {
$push: {
status: "$_id.status",
final: "$final",
start: "$start"
}
}
}
},
{
$project: {
key: "$_id",
status_map: 1,
_id: 0
}
}
])
添加到@Tom Slabbaert 的回答,
这里,final 和 start 数组的格式是 array of array
。但它必须只是一个 array
.
可以通过在 status_map
上使用 $unwind
和在 status_map.final
和 status_map.start
数组上使用 $reduce
来实现。
最终查询:
db.collection.aggregate([
{
$project: {
concat: {
$concatArrays: [
"$final",
"$start"
]
}
}
},
{
$unwind: "$concat"
},
{
$unwind: "$concat.status_map"
},
{
$group: {
_id: {
k: "$concat.key",
status: "$concat.status_map.status"
},
final: {
$push: "$concat.status_map.final"
},
start: {
$push: "$concat.status_map.start"
}
}
},
{
$group: {
_id: "$_id.k",
status_map: {
$push: {
status: "$_id.status",
final: "$final",
start: "$start"
}
}
}
},
{
$project: {
key: "$_id",
status_map: 1,
_id: 0
}
},
{
$unwind: "$status_map"
},
{
$project: {
key: 1,
"status_map.status": 1,
final: {
$reduce: {
input: "$status_map.final",
initialValue: [],
in: {
$concatArrays: [
"$$value",
"$$this"
]
}
}
},
start: {
$reduce: {
input: "$status_map.start",
initialValue: [],
in: {
$concatArrays: [
"$$value",
"$$this"
]
}
}
}
}
},
{
$group: {
_id: "$key",
status_map: {
$push: {
status: "$status_map.status",
final: "$final",
start: "$start"
}
}
}
}
])
有几种方法可以解决这个问题,不一定是 $mergeObjects
。但是既然你提到了 $mergeObjects
这是一个使用它的人:
请注意,使用这种方法,我们将合并具有相同键和状态的对象,如果多个文档存在相同的键,则数组中的值将不会被连接,数组将被替换。
db.collection.aggregate([
{
$project: {
all: { $concatArrays: ["$final","$start"] }
}
},
{
$unwind: "$all"
},
{
$unwind: "$all.status_map"
},
{
$group: {
_id: {
_id: "$_id", // keep _id in $group to apply the group for each document, otherwise if you want to apply group on all documents, omit this
key: "$all.key",
status: "$all.status_map.status"
},
status_map: { $mergeObjects: "$$ROOT.all.status_map" }
}
},
{ // some data don't have start or end at all, we have to set a default empty array
$addFields: { // you can skip this stage if you allow data without start and final keys
"status_map.start": { $ifNull: ["$status_map.start", []] },
"status_map.final": { $ifNull: ["$status_map.final", []] }
}
},
{
$group: {
_id: { _id: "$_id._id", key: "$_id.key" },
key: { $first: "$_id.key" },
status_map: { $push: "$status_map" }
}
}
])
我正在尝试合并聚合管道中的两个数组。执行 $facet 后,我的 MongoDB 文档具有以下格式:
{
"final": [
{
"key": "TP-1",
"status_map": [
{ "status": "Closed", "final": [ "a", "b"]},
{ "status": "Done", "final": ["c","d" ] }
]
},
{
"key": "TP-2",
"status_map": [
{ "status": "Closed", "final": [ "x","y"] }
]
}
],
"start": [
{
"key": "TP-1",
"status_map": [
{ "status": "Closed", "start": [ "h"]},
{ "status": "Done", "start": ["a"]}
]
},
{
"key": "TP-2",
"status_map": [{ "status": "Done", "start": ["l","m"]}
]
}
]
}
预期输出:
我需要合并对应两组的final
和start
数组:
- 基于
key
然后 - 基于
status
{
"data": [
{
"key": "TP-1",
"status_map": [
{ "status": "Closed","final": ["a","b"],"start":["h"]},
{ "status": "Done","final": ["c","d"],"start":["a"]}
]
},
{
"key": "TP-2",
"status_map": [
{ "status": "Closed", "final":[ "x","y"],"start": []},
{ "status": "Done", "final": [ ],"start": [ "l","m"]}
]
}
]
}
如何实现这个用例?
在没有任何假设的情况下(例如,两个键总是出现),我的策略是连接两个数组,展开并最终按键分组。
db.collection.aggregate([
{
$project: {
concat: {
$concatArrays: [
"$final",
"$start"
]
}
}
},
{
$unwind: "$concat"
},
{
$unwind: "$concat.status_map"
},
{
$group: {
_id: {
k: "$concat.key",
status: "$concat.status_map.status"
},
final: {
$push: "$concat.status_map.final"
},
start: {
$push: "$concat.status_map.start"
}
}
},
{
$group: {
_id: "$_id.k",
status_map: {
$push: {
status: "$_id.status",
final: "$final",
start: "$start"
}
}
}
},
{
$project: {
key: "$_id",
status_map: 1,
_id: 0
}
}
])
添加到@Tom Slabbaert 的回答,
这里,final 和 start 数组的格式是 array of array
。但它必须只是一个 array
.
可以通过在 status_map
上使用 $unwind
和在 status_map.final
和 status_map.start
数组上使用 $reduce
来实现。
最终查询:
db.collection.aggregate([
{
$project: {
concat: {
$concatArrays: [
"$final",
"$start"
]
}
}
},
{
$unwind: "$concat"
},
{
$unwind: "$concat.status_map"
},
{
$group: {
_id: {
k: "$concat.key",
status: "$concat.status_map.status"
},
final: {
$push: "$concat.status_map.final"
},
start: {
$push: "$concat.status_map.start"
}
}
},
{
$group: {
_id: "$_id.k",
status_map: {
$push: {
status: "$_id.status",
final: "$final",
start: "$start"
}
}
}
},
{
$project: {
key: "$_id",
status_map: 1,
_id: 0
}
},
{
$unwind: "$status_map"
},
{
$project: {
key: 1,
"status_map.status": 1,
final: {
$reduce: {
input: "$status_map.final",
initialValue: [],
in: {
$concatArrays: [
"$$value",
"$$this"
]
}
}
},
start: {
$reduce: {
input: "$status_map.start",
initialValue: [],
in: {
$concatArrays: [
"$$value",
"$$this"
]
}
}
}
}
},
{
$group: {
_id: "$key",
status_map: {
$push: {
status: "$status_map.status",
final: "$final",
start: "$start"
}
}
}
}
])
有几种方法可以解决这个问题,不一定是 $mergeObjects
。但是既然你提到了 $mergeObjects
这是一个使用它的人:
请注意,使用这种方法,我们将合并具有相同键和状态的对象,如果多个文档存在相同的键,则数组中的值将不会被连接,数组将被替换。
db.collection.aggregate([
{
$project: {
all: { $concatArrays: ["$final","$start"] }
}
},
{
$unwind: "$all"
},
{
$unwind: "$all.status_map"
},
{
$group: {
_id: {
_id: "$_id", // keep _id in $group to apply the group for each document, otherwise if you want to apply group on all documents, omit this
key: "$all.key",
status: "$all.status_map.status"
},
status_map: { $mergeObjects: "$$ROOT.all.status_map" }
}
},
{ // some data don't have start or end at all, we have to set a default empty array
$addFields: { // you can skip this stage if you allow data without start and final keys
"status_map.start": { $ifNull: ["$status_map.start", []] },
"status_map.final": { $ifNull: ["$status_map.final", []] }
}
},
{
$group: {
_id: { _id: "$_id._id", key: "$_id.key" },
key: { $first: "$_id.key" },
status_map: { $push: "$status_map" }
}
}
])