[英]MongoDB aggregation $lookup to parent array field with pipeline syntax and _id as string
I have the following collections in my MongoDB (v.4.4):我的 MongoDB (v.4.4) 中有以下 collections:
guilds
: guilds
:
{
_id: String,
members: [{ _id String, rank: number },{ _id String, rank: number }...]
}
and characters
:和characters
:
{
_id: String,
many_other: 'fields'
}
And I'd like to join with the $lookup
pipeline syntax guild.members <= characters
by _id
field.我想加入$lookup
管道语法guild.members <= characters
by _id
字段。
I don't use Mongo build-in
OjbectIds
as_id
, I overwrite it with strings in both collections.我不使用 Mongo 内置OjbectIds
作为_id
,我用 collections 中的字符串覆盖它。 As I heard, there is a bit different behaviour with$lookup
with strings as_id
in pipelines.正如我所听到的,在管道中使用字符串作为_id
的$lookup
有一些不同的行为。 So make sure, that you knew about it, before answering.因此,在回答之前,请确保您对此有所了解。
The expected result that I want is simple, I'd like to save rank from the original document, and also add any other field from $lookup
it:我想要的预期结果很简单,我想从原始文档中保存排名,并从$lookup
添加任何其他字段:
{
_id: String // (guild)
members: [
{
_id: String, // (characters)
rank: number,
many_other: '...fields from characters'
},
{
_id: String, // (characters)
rank: number,
many_other: '...fields from characters'
}, ...
]
Mongo Playground example: avaliable Mongo Playground 示例:可用
What have I tried:我尝试了什么:
Various queries, like:各种查询,例如:
{
$lookup: {
from: "characters",
pipeline: [
{
$match: {
$expr: { $eq: [ { $toString :"$members._id" }, { $toString : "$$character_id" } ] }
}
}
],
as: "guild_members"
},
}
With converting ID's to string, with let
stages variables, and using $map
operator.将 ID 转换为字符串,使用let
阶段变量,并使用$map
运算符。 But I still far away from the required result.但我离要求的结果还很远。
There is also another problem, which is some relevance to the question, but not related to queries itself还有一个问题,和问题有些相关,但和查询本身无关
As you may see, the characters
collection has many other fields
.如您所见, characters
集合还有many other fields
。 Some of them are pretty heavy, (because guilds can have up to 500 members) which making the result document >16 MB (MongoDB threshold limit) which gives an error.其中一些非常重,(因为公会最多可以有 500 个成员)这使得结果文档 >16 MB(MongoDB 阈值限制),这会产生错误。 Since, as far as I know, we could not pick fields from joined
documents, it will be much better to exclude it right after the $lookup
stage or something like that.因为,据我所知,我们无法从joined
的文档中选择字段,所以最好在$lookup
阶段或类似的阶段之后立即排除它。 Any advice about it will be pretty welcome.任何关于它的建议都将非常受欢迎。
Lookup with pipeline is not required, when you pass members._id
as localField,当您将members._id
作为 localField 传递时,不需要使用管道查找,
$lookup
with characters and pass members._id
as localField $lookup
与字符和传递members._id
作为 localField$map
to iterate loop of members
array $map
迭代members
数组的循环$filter
to iterate loop of members_guid
and get matching member $filter
迭代members_guid
的循环并获取匹配的成员$arrayElemAt
to get first matching element from above filter $arrayElemAt
从上面的过滤器中获取第一个匹配元素$mergeObjects
to merge current fields with above filtered object of member $mergeObjects
将当前字段与上面过滤的成员 object 合并db.guilds.aggregate([
{
$lookup: {
from: "characters",
localField: "members._id",
foreignField: "_id",
as: "members_guid"
}
},
{
$project: {
members: {
$map: {
input: "$members",
as: "m",
in: {
$mergeObjects: [
"$$m",
{
$arrayElemAt: [
{
$filter: {
input: "$members_guid",
cond: { $eq: ["$$this._id", "$$m._id"] }
}
},
0
]
}
]
}
}
}
}
}
])
I take the @turivishal answer since the old-style-native aggregation is much easier to understand than pipeline
syntax.我接受@turivishal 的回答,因为旧式原生聚合比pipeline
语法更容易理解。 But if someone is interested, my old part of aggregation, which I used a while ago.但如果有人感兴趣,我之前使用过的旧聚合部分。
db.guilds.aggregate([
{
$lookup: {
from: "characters",
let: {
members: "$members"
},
pipeline: [
{
$match: {
$expr: {
$in: [
"$_id",
"$$members._id"
]
}
}
},
{
$addFields: {
rank: {
$reduce: {
input: "$$members",
initialValue: null,
in: {
$cond: [
{
$eq: [
"$$this._id",
"$_id"
]
},
"$$this.rank",
"$$value"
]
}
}
}
}
}
],
as: "members"
},
}
])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.