0

My goal is to get all 'student' documents that belong to 'classes' that have at least one student of grade "blue" and at least one of grade "red".

I am inclined to simply do a sequence of queries in Python (pymongo), tackling the task directly.

I wonder if there is some clever aggregation pipeline that I could use!

Given:

Classes collection:

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

Students collection:

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

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

1 Answer 1

1

You could use :

  • a $group to group by class_id and $push all grade in an array so we can deduce easily in the next step which class "contains" blue. Preserve the current document with $$ROOT because we'll need the students that match the class_id

  • a $match to match only classes that have grade blue in it

  • an $unwind to remove the array of students generated by previous $$ROOT

  • a $project to reorganize your document nicely

Query would be :

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",
    }
}])

If you need to match other color than ["blue","red"] you can add more in the $match aggregation ($in: ["blue","red","yellow"])

For implementing it in PyMongo, it is very straightforward :

from pymongo import MongoClient
import pprint

db = MongoClient().testDB

pipeline = [ <the_aggregation_query_here> ]

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

Additionnaly, to match only students that belong to classes collection, perform a $lookup and match those that are not empty. Add the following at the aggregation query :

{
    $lookup: {
        from: "classes",
        localField: "class_id",
        foreignField: "class_id",
        as: "class"
    }
}, {
    $match: {
        "class": { $not: { $size: 0 } }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.