MongoDB 聚合 $lookup 到具有管道语法和 _id 作为字符串的父数组字段
Posted
技术标签:
【中文标题】MongoDB 聚合 $lookup 到具有管道语法和 _id 作为字符串的父数组字段【英文标题】:MongoDB aggregation $lookup to parent array field with pipeline syntax and _id as string 【发布时间】:2021-08-05 05:25:44 【问题描述】:我的 MongoDB (v.4.4) 中有以下集合:
guilds
:
_id: String,
members: [ _id String, rank: number , _id String, rank: number ...]
和characters
:
_id: String,
many_other: 'fields'
我想通过_id
字段加入$lookup
管道语法guild.members <= characters
。
我不使用 Mongo 内置
OjbectIds
作为_id
,我用两个集合中的字符串覆盖它。正如我所听到的,$lookup
与管道中的字符串为_id
有一些不同的行为。所以在回答之前,请确保你知道它。
我想要的预期结果很简单,我想从原始文档中保存排名,并从$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
我尝试了什么:
各种查询,例如:
$lookup:
from: "characters",
pipeline: [
$match:
$expr: $eq: [ $toString :"$members._id" , $toString : "$$character_id" ]
],
as: "guild_members"
,
将 ID 转换为字符串,使用 let
阶段变量,并使用 $map
运算符。但我离要求的结果还很远。
还有一个问题,就是和问题有些相关,但和查询本身无关
如您所见,characters
集合具有many other fields
。其中一些非常重,(因为公会最多可以有 500 个成员)这使得结果文档 >16 MB(MongoDB 阈值限制),这会产生错误。因为据我所知,我们无法从joined
文档中选择字段,所以最好在$lookup
阶段或类似的东西之后立即排除它。任何关于它的建议都会非常受欢迎。
【问题讨论】:
【参考方案1】:不需要使用管道查找,当您将 members._id
作为 localField 传递时,
$lookup
带字符并将 members._id
作为 localField 传递
$map
迭代 members
数组的循环
$filter
迭代 members_guid
的循环并获取匹配的成员
$arrayElemAt
从上面的过滤器中获取第一个匹配元素
$mergeObjects
将当前字段与上面过滤的成员对象合并
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
]
]
])
Playground
【讨论】:
查询没问题,我也有一个,问题有点大。在$lookup
阶段之前或之后,要从加入的文档 (characters
) 中删除/排除某些字段是什么?例如 (characters.pets
)。在这种情况下,我可以在$project
阶段,在$map
中简单地删除它们。我说的对吗?
可以,但最好在添加额外的项目阶段删除,请参阅playground【参考方案2】:
我接受@turivishal 的答案,因为旧式原生聚合比pipeline
语法更容易理解。但是如果有人感兴趣,我之前使用过的聚合的旧部分。
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"
,
])
【讨论】:
以上是关于MongoDB 聚合 $lookup 到具有管道语法和 _id 作为字符串的父数组字段的主要内容,如果未能解决你的问题,请参考以下文章