用于查找和合并嵌套文档的聚合管道
Aggregation pipeline to lookup and merge nested documents
我正在努力编写一个聚合管道以通过它们的 _id 和 return 特定名称查找嵌套文档,而不会覆盖数据中现有的 keys/values。我已经设法为嵌套数组执行此操作,但无法为嵌套在嵌套数组中的数组执行此操作。
所以我想查找每种成分和每个子成分的 _id,并将它们与这些已经存在的成分(即数量、度量)的数据合并。
这是我目前的情况:
https://mongoplayground.net/p/ft4oIMm_8wg
产品合集:
[
{
"_id": {
"$oid": "5ecf269bceb735416db0b329"
},
"id": 36,
"title": "Product 1",
"description": {
"generalInformation": "Some information",
"activeIngredients": [
{
"_id": 1636,
"qty": 133.5,
"measure": "µg",
"subIngredient": [
{
"_id": 1626,
"qty": 16.6,
"measure": "µg"
}
],
},
{
"_id": 1234,
"qty": 133.5,
"measure": "µg",
"subIngredient": [
{
"_id": 1122,
"qty": 16.6,
"measure": "µg"
},
{
"_id": 1212,
"qty": 16.6,
"measure": "µg"
}
],
},
]
},
},
{
"_id": {
"$oid": "5ecf269bceb735416db0b346"
},
"id": 36,
"title": "Product 2",
"description": {
"generalInformation": "Some information",
"activeIngredients": [
{
"_id": 1234,
"qty": 133.5,
"measure": "µg",
"subIngredient": [
{
"_id": 1122,
"qty": 16.6,
"measure": "µg"
}
],
},
{
"_id": 1234,
"qty": 133.5,
"measure": "µg",
"subIngredient": [
{
"_id": 1122,
"qty": 16.6,
"measure": "µg"
},
{
"_id": 1212,
"qty": 16.6,
"measure": "µg"
}
],
},
]
},
}
]
成分收集:
[
{
"_id": 1234,
"name": "Ingredient 1",
},
{
"_id": 1122,
"name": "Ingredient 2",
},
{
"_id": 1212,
"name": "Ingredient 3",
},
{
"_id": 1636,
"name": "Ingredient 4",
},
{
"_id": 1626,
"name": "Ingredient 5",
}
]
应该 return编辑什么:
[
{
"_id": ObjectId("5ecf269bceb735416db0b329"),
"title": "Product 1"
"description": {
"activeIngredients": {
"_id": 1636,
"measure": "µg",
"name": "Ingredient 4",
"qty": 133.5,
"subIngredient": [
{
"_id": 1626,
"measure": "µg",
"qty": 16.6
}
]
},
"generalInformation": "Some information"
},
"ingredients": [
{
"_id": 1636,
"measure": "µg",
"name": "Ingredient 4",
"qty": 133.5,
"subIngredient": [
{
"_id": 1626,
"measure": "µg",
"qty": 16.6,
"name": "Ingredient 2"
}
]
},
{
"_id": 1234,
"measure": "µg",
"name": "Ingredient 1",
"qty": 133.5,
"subIngredient": [
{
"_id": 1122,
"measure": "µg",
"qty": 16.6,
"name": "Ingredient 2"
},
{
"_id": 1212,
"measure": "µg",
"qty": 16.6,
"name": "Ingredient 2"
}
]
}
]
},
]
我当前的管道:
[
{
"$unwind": {
"path": "$description.activeIngredients",
"preserveNullAndEmptyArrays": false
}
},
{
"$lookup": {
"from": "ingredients",
"localField": "description.activeIngredients._id",
"foreignField": "_id",
"as": "description.activeIngredients.name"
}
},
{
"$addFields": {
"description.activeIngredients.name": {
"$arrayElemAt": [
"$description.activeIngredients.name.name",
0
]
}
}
},
{
"$group": {
"_id": "$_id",
"ingredients": {
"$push": "$description.activeIngredients"
},
"description": {
"$first": "$description"
},
"title": {
"$first": "$title"
}
}
},
{
"$lookup": {
"from": "ingredients",
"localField": "ingredients.subIngredient._id",
"foreignField": "_id",
"as": "subIngredients"
}
}
]
感谢任何帮助。谢谢。
你离得不远了,你可以通过多种不同的方式实现这个结果,其中之一就是 $unwind
subingredients
数组,$lookup
然后最后添加另一个 $group
阶段来重组文档。
正如你清楚地表明你知道如何做所有这些事情,我将展示一种不同的方式来利用像 $map, $indexOfArray and Mongo's v3.6 $lookup 语法这样的运算符。
我们的策略不是展开子数组,而是 $lookup
所有相关 sub-ingredients,然后使用我指定的运算符“合并”两个数组。
即服用:
[ {id: 5, name: "name"} ];
[ {id: 5, qty: 25} ]
并将它们制作成:
[ {id: 5, name: "name", qty: 25} ]
我们是这样做的:
db.products.aggregate([
{
"$unwind": {
"path": "$description.activeIngredients",
"preserveNullAndEmptyArrays": false
}
},
{
"$lookup": {
"from": "ingredients",
"localField": "description.activeIngredients._id",
"foreignField": "_id",
"as": "description.activeIngredients.name"
}
},
{
"$addFields": {
"description.activeIngredients.name": {
"$arrayElemAt": [
"$description.activeIngredients.name.name",
0
]
}
}
},
{
"$lookup": {
"from": "ingredients",
"let": {
sub: "$description.activeIngredients.subIngredient"
},
"pipeline": [
{
$match: {
$expr: {
"$setIsSubset": [
[
"$_id"
],
{
$map: {
input: "$$sub",
as: "datum",
in: "$$datum._id"
}
}
]
}
}
}
],
"as": "subIngredients"
}
},
{
"$addFields": {
"description.activeIngredients.subIngredient": {
$map: {
input: "$description.activeIngredients.subIngredient",
as: "sub",
in: {
"$mergeObjects": [
"$$sub",
{
name: {
$arrayElemAt: [
"$subIngredients.name",
{
"$indexOfArray": [
"$subIngredients._id",
"$$sub._id"
]
}
]
}
}
]
}
}
}
}
},
{
"$group": {
"_id": "$_id",
"ingredients": {
"$push": "$description.activeIngredients"
},
"description": {
"$first": "$description"
},
"title": {
"$first": "$title"
}
}
}
])
我正在努力编写一个聚合管道以通过它们的 _id 和 return 特定名称查找嵌套文档,而不会覆盖数据中现有的 keys/values。我已经设法为嵌套数组执行此操作,但无法为嵌套在嵌套数组中的数组执行此操作。
所以我想查找每种成分和每个子成分的 _id,并将它们与这些已经存在的成分(即数量、度量)的数据合并。
这是我目前的情况: https://mongoplayground.net/p/ft4oIMm_8wg
产品合集:
[
{
"_id": {
"$oid": "5ecf269bceb735416db0b329"
},
"id": 36,
"title": "Product 1",
"description": {
"generalInformation": "Some information",
"activeIngredients": [
{
"_id": 1636,
"qty": 133.5,
"measure": "µg",
"subIngredient": [
{
"_id": 1626,
"qty": 16.6,
"measure": "µg"
}
],
},
{
"_id": 1234,
"qty": 133.5,
"measure": "µg",
"subIngredient": [
{
"_id": 1122,
"qty": 16.6,
"measure": "µg"
},
{
"_id": 1212,
"qty": 16.6,
"measure": "µg"
}
],
},
]
},
},
{
"_id": {
"$oid": "5ecf269bceb735416db0b346"
},
"id": 36,
"title": "Product 2",
"description": {
"generalInformation": "Some information",
"activeIngredients": [
{
"_id": 1234,
"qty": 133.5,
"measure": "µg",
"subIngredient": [
{
"_id": 1122,
"qty": 16.6,
"measure": "µg"
}
],
},
{
"_id": 1234,
"qty": 133.5,
"measure": "µg",
"subIngredient": [
{
"_id": 1122,
"qty": 16.6,
"measure": "µg"
},
{
"_id": 1212,
"qty": 16.6,
"measure": "µg"
}
],
},
]
},
}
]
成分收集:
[
{
"_id": 1234,
"name": "Ingredient 1",
},
{
"_id": 1122,
"name": "Ingredient 2",
},
{
"_id": 1212,
"name": "Ingredient 3",
},
{
"_id": 1636,
"name": "Ingredient 4",
},
{
"_id": 1626,
"name": "Ingredient 5",
}
]
应该 return编辑什么:
[
{
"_id": ObjectId("5ecf269bceb735416db0b329"),
"title": "Product 1"
"description": {
"activeIngredients": {
"_id": 1636,
"measure": "µg",
"name": "Ingredient 4",
"qty": 133.5,
"subIngredient": [
{
"_id": 1626,
"measure": "µg",
"qty": 16.6
}
]
},
"generalInformation": "Some information"
},
"ingredients": [
{
"_id": 1636,
"measure": "µg",
"name": "Ingredient 4",
"qty": 133.5,
"subIngredient": [
{
"_id": 1626,
"measure": "µg",
"qty": 16.6,
"name": "Ingredient 2"
}
]
},
{
"_id": 1234,
"measure": "µg",
"name": "Ingredient 1",
"qty": 133.5,
"subIngredient": [
{
"_id": 1122,
"measure": "µg",
"qty": 16.6,
"name": "Ingredient 2"
},
{
"_id": 1212,
"measure": "µg",
"qty": 16.6,
"name": "Ingredient 2"
}
]
}
]
},
]
我当前的管道:
[
{
"$unwind": {
"path": "$description.activeIngredients",
"preserveNullAndEmptyArrays": false
}
},
{
"$lookup": {
"from": "ingredients",
"localField": "description.activeIngredients._id",
"foreignField": "_id",
"as": "description.activeIngredients.name"
}
},
{
"$addFields": {
"description.activeIngredients.name": {
"$arrayElemAt": [
"$description.activeIngredients.name.name",
0
]
}
}
},
{
"$group": {
"_id": "$_id",
"ingredients": {
"$push": "$description.activeIngredients"
},
"description": {
"$first": "$description"
},
"title": {
"$first": "$title"
}
}
},
{
"$lookup": {
"from": "ingredients",
"localField": "ingredients.subIngredient._id",
"foreignField": "_id",
"as": "subIngredients"
}
}
]
感谢任何帮助。谢谢。
你离得不远了,你可以通过多种不同的方式实现这个结果,其中之一就是 $unwind
subingredients
数组,$lookup
然后最后添加另一个 $group
阶段来重组文档。
正如你清楚地表明你知道如何做所有这些事情,我将展示一种不同的方式来利用像 $map, $indexOfArray and Mongo's v3.6 $lookup 语法这样的运算符。
我们的策略不是展开子数组,而是 $lookup
所有相关 sub-ingredients,然后使用我指定的运算符“合并”两个数组。
即服用:
[ {id: 5, name: "name"} ];
[ {id: 5, qty: 25} ]
并将它们制作成:
[ {id: 5, name: "name", qty: 25} ]
我们是这样做的:
db.products.aggregate([
{
"$unwind": {
"path": "$description.activeIngredients",
"preserveNullAndEmptyArrays": false
}
},
{
"$lookup": {
"from": "ingredients",
"localField": "description.activeIngredients._id",
"foreignField": "_id",
"as": "description.activeIngredients.name"
}
},
{
"$addFields": {
"description.activeIngredients.name": {
"$arrayElemAt": [
"$description.activeIngredients.name.name",
0
]
}
}
},
{
"$lookup": {
"from": "ingredients",
"let": {
sub: "$description.activeIngredients.subIngredient"
},
"pipeline": [
{
$match: {
$expr: {
"$setIsSubset": [
[
"$_id"
],
{
$map: {
input: "$$sub",
as: "datum",
in: "$$datum._id"
}
}
]
}
}
}
],
"as": "subIngredients"
}
},
{
"$addFields": {
"description.activeIngredients.subIngredient": {
$map: {
input: "$description.activeIngredients.subIngredient",
as: "sub",
in: {
"$mergeObjects": [
"$$sub",
{
name: {
$arrayElemAt: [
"$subIngredients.name",
{
"$indexOfArray": [
"$subIngredients._id",
"$$sub._id"
]
}
]
}
}
]
}
}
}
}
},
{
"$group": {
"_id": "$_id",
"ingredients": {
"$push": "$description.activeIngredients"
},
"description": {
"$first": "$description"
},
"title": {
"$first": "$title"
}
}
}
])