MongoDB分组任务-多组,条件

MongoDB grouping task - multiple groups, conditions

我的目标是获取属于 'classes' 的所有 'student' 个文档 至少有一名年级 "blue" 的学生和至少一名 年级 "red".

我倾向于在 Python (pymongo) 中简单地执行一系列查询,直接处理任务。

我想知道是否有一些我可以使用的聪明的聚合管道!

鉴于:

类 collection:

{ class_id: 'a' }
{ class_id: 'b' }

学生collection:

{ class_id: 'a',
grade: 'blue' }

{class_id: 'a',
grade: 'red' }

您可以使用:

  • a $group 按数组中的 class_id$push 所有等级进行分组,这样我们就可以在下一步中轻松推断出 class "contains" blue。使用 $$ROOT 保留当前文档,因为我们需要匹配 class_id

  • 的学生
  • a $match 仅匹配 class 具有等级 blue 的课程

  • an $unwind 删除之前 $$ROOT

  • 生成的学生数组
  • a $project 很好地重组您的文档

查询将是:

db.students.aggregate([{
    "$group": {
        "_id": "$class_id",
        "grades": { "$push": "$grade" },
        "students": { "$push": "$$ROOT" }
    }
}, {
    "$match": {
        "grades": { "$all": ["blue","red"] }
    }
}, {
    "$unwind": "$students"
}, {
    "$project": {
        "_id": "$students._id",
        "class_id": "$students.class_id",
        "grade": "$students.grade",
    }
}])

如果您需要匹配除 ["blue","red"] 之外的其他颜色,您可以在 $match 聚合中添加更多 ($in: ["blue","red","yellow"])

在 PyMongo 中实现它非常简单:

from pymongo import MongoClient
import pprint

db = MongoClient().testDB

pipeline = [ <the_aggregation_query_here> ]

pprint.pprint(list(db.students.aggregate(pipeline)))

此外,要仅匹配属于 classes 集合的学生,请执行 $lookup 并匹配不为空的学生。在聚合查询中添加以下内容:

{
    $lookup: {
        from: "classes",
        localField: "class_id",
        foreignField: "class_id",
        as: "class"
    }
}, {
    $match: {
        "class": { $not: { $size: 0 } }
    }
}