如何将由ObjectId对和相关集合组成的数组进行聚合
如何将由ObjectId对和相关集合组成的数组进行聚合
我有一个课程集合,我正在为该课程的每个科目分配教师。分配结果保存为一个JSON数组,请参考下面的参考文档。
我正在尝试将两个不同集合中的科目和教师字段与其文档进行匹配。我可以将它们分别获取为两个不同的数组,但无法按照我期望的输出结构获取它们。
教师集合中的文档:
{
_id: ObjectId("5cbee0e37a3c852868ec9797"),
name: "Alister"
}
科目集合中的文档:
{
_id: ObjectId("5cc3f7cc88e95a0c8e8ccd7d"),
name: "English",
code: "EN"
}
我尝试的查询:
Course.aggregate([
{"$match": matchQuery},
{"$lookup": {
"from": "subjects",
"localField": "allotment.subject",
"foreignField": "_id",
"as": "subjectInfo"
}},
{"$lookup": {
"from": "teachers",
"localField": "allotment.teacher",
"foreignField": "_id",
"as": "teacherInfo"}
},
])
该查询的输出:
{
isAssigned: true,
name: "11",
section: "A",
subjectInfo:[
{_id: "5cc3f7cc88e95a0c8e8ccd7d", name:"English", code:"EN"},
{_id: "5cc3f80e88e95a0c8e8ccd7e", name: "Science", code:"SC"}
],
teacherInfo:[
{_id: ObjectId("5cbee0e37a3c852868ec9797"),name: "Alister"},
{ _id: ObjectId("5cbee10c7a3c852868ec9798"),name: "Frank"}
]
}
期望的输出:
{
"_id" : ObjectId("5cc7d72d8e165005cbef939e"),
"isAssigned" : true,
"name" : "11",
"section" : "A",
"allotment" : [
{
"subject" : {
_id: ObjectId("5cc3f7cc88e95a0c8e8ccd7d"),
name: "English",
code: "EN"
},
"teacher" : {
_id: ObjectId("5cbee0e37a3c852868ec9797"),
name: "Alister"
}
},
{
"subject" : {
_id: ObjectId("5cc3f80e88e95a0c8e8ccd7e"),
name: "Science",
code: "SC"
},
"teacher" : {
_id: ObjectId("5cbee10c7a3c852868ec9798"),
name: "Frank"
}
}
]
}
这篇文章将介绍如何使用聚合查询在MongoDB中汇总ObjectId对的数组以及相关的集合。
问题的原因是需要将一个包含ObjectId对的数组与相关的集合进行汇总。解决方法是使用聚合查询,首先使用$unwind操作符展开allotment数组,然后使用$lookup操作符关联subject集合,并重复相同步骤关联teachers集合,最后使用$group操作符将它们合并回数组中。
以下是我尝试并成功运行的聚合查询:
Course.aggregate([ {"$match": matchQuery}, { $unwind: '$allotment' }, { $lookup:{ "from": "subjects", "localField": "allotment.subject", "foreignField": "_id", "as": "allotment.subject" } }, { $unwind: '$allotment.subject' }, { "$lookup": { "from": "teachers", "localField": "allotment.teacher", "foreignField": "_id", "as": "allotment.teacher" } }, { $unwind: '$allotment.teacher' }, { "$group" : { "_id" : "$_id", "isAssigned" : { "$first" : "$isAssigned" }, "name" : { "$first" : "$name" }, "section" : { "$first" : "$section" }, "allotment" : { "$addToSet" : "$allotment" } } } ])
以上就是如何使用聚合查询在MongoDB中汇总ObjectId对的数组以及相关的集合的方法。通过这个方法,我们可以轻松地将数组中的ObjectId与其他集合中的相关数据关联起来。
问题的出现原因是需要通过ObjectId对数组进行聚合,并与相关的集合进行连接。解决方法是使用MongoDB的聚合操作符$lookup,它允许在聚合过程中连接集合。
具体解决方法如下所示:
1. 使用$unwind将数组展开,将每个元素作为独立的文档处理。
2. 使用$lookup操作符连接subjects集合,通过localField和foreignField指定连接的字段,将结果存储在allotment.subject字段中。
3. 使用$lookup操作符连接teachers集合,通过localField和foreignField指定连接的字段,将结果存储在allotment.teacher字段中。
4. 使用$addFields操作符将allotment.subject和allotment.teacher数组中的第一个元素赋值给相应的字段。
5. 使用$group操作符将结果按_id字段进行分组,将isAssigned、name、section和allotment字段的值分别取第一个值,将allotment字段的值存储为数组。
完整的聚合管道如上所示。
这样,通过以上的聚合操作,就可以实现对数组的ObjectId进行聚合,并与相关的集合进行连接。
问题出现的原因:
在对ObjectId对数组进行聚合时,需要将其与相关的集合进行关联,但是在使用$lookup操作符时,可能会出现无法正确匹配的问题。
解决方法:
可以在进行关联查询之前,先对数组进行解构(unwind),然后再进行关联查询。这样可以确保每个ObjectId对都能正确匹配到对应的集合。
具体实现代码如下:
Course.aggregate([ {"$match": matchQuery}, {"$unwind": "$allotment"}, {"$lookup": { "from": "subjects", "localField": "allotment.subject", "foreignField": "_id", "as": "subjectInfo" }}, {"$lookup": { "from": "teachers", "localField": "allotment.teacher", "foreignField": "_id", "as": "teacherInfo" }}, ])
如果希望在恢复预期格式后重新分组,可以添加以下代码:
{ $group : { _id: "$_id", name: {$first: "$name"}, section: {$first: "$section"}, isAssigned: {$first: "$isAssigned"}, allotment: {$push: {teacher: "$teacherInfo.0", subject: "$subjectInfo.0"}} }}
这里假设teacherInfo和subjectInfo永远不为空,如果不是这种情况,则需要添加$match来过滤空值。