我必须在MongoDB中编写一个聚合查询,其中从源集合到目标集合的$lookup
可以来自多个字段。即来自源集合的多个字段(所有ID(可以链接到目标集合中的单个字段。
换句话说,我的$lookup
中的localfield
具有$or
条件:
学生:
{
"_id": : {
"$oid": "61c32b08c6056d28db6550b5"
},
"name": "Jack Sparrow",
"course1": : {
"$oid": "82d77b08c6056d28db65ca98"
},
"course2": : {
"$oid": "45d22b08c6056d28db688013"
},
"course3": : {
"$oid": "98a72b08c6056d28db6561d6"
},
"course4": : {
"$oid": "10b22b08c6056d28db6576b1"
}
}
查询:
{
$lookup: {
'from': 'courses',
'localField': 'course1', 'course2', 'course3', 'course4'
'foreignField': '_id',
'as': 'studentCourses'
}
}
在这种情况下,源集合表示students
,而目标集合是courses
。源表中的课程数量可以最小为1,最大为4。其中任何一个都可以与课程集合中的课程相关。
我怎样才能做到这一点?
localField
只能支持string
类型的值,该值表示字段名称。
在查找带管道的$lookup
时,通过将这些course
字段设置为courses
数组,并在查找管道中使用$in
运算符执行筛选。
db.students.aggregate([
{
$lookup: {
"from": "courses",
"let": {
courses: [
"$course1",
"$course2",
"$course3",
"$course4"
]
},
"pipeline": [
{
$match: {
$expr: {
$in: [
"$_id",
"$$courses"
]
}
}
}
],
"as": "studentCourses"
}
}
])
演示@Mongo Playground
意见:
认为你的学生模式不是一个好的设计。你可能会想,学生们可能会选修不同数量的课程。可能引用的"课程"字段可能不存在。或者,如果每次都添加/删除了"课程"字段,则需要再次修改查询。您应该考虑一个
course
数组字段来存储这些course<X>
id
您可以参考下面的查询,而不是硬编码字段名称,我们用包含前缀的字段获得值:";课程";。
db.students.aggregate([
{
$lookup: {
"from": "courses",
"let": {
courses: {
$reduce: {
input: {
$filter: {
input: {
$objectToArray: "$$ROOT"
},
cond: {
"$regexMatch": {
"input": "$$this.k",
"regex": "^course[\d]$"
}
}
}
},
initialValue: [],
in: {
$concatArrays: [
"$$value",
[
"$$this.v"
]
]
}
}
}
},
"pipeline": [
{
$match: {
$expr: {
$in: [
"$_id",
"$$courses"
]
}
}
}
],
"as": "studentCourses"
}
}
])
演示2@Mongo Playground