งานการจัดกลุ่ม MongoDB - หลายกลุ่ม เงื่อนไข

เป้าหมายของฉันคือการได้รับเอกสาร 'นักเรียน' ทั้งหมดที่เป็นของ 'ชั้นเรียน' ที่มีนักเรียนเกรด "สีน้ำเงิน" อย่างน้อยหนึ่งคนและเกรด "สีแดง" อย่างน้อยหนึ่งคน

ฉันมีแนวโน้มที่จะทำลำดับการสืบค้นใน Python (pymongo) เพื่อจัดการงานโดยตรง

ฉันสงสัยว่ามีไปป์ไลน์การรวมกลุ่มที่ชาญฉลาดที่ฉันสามารถใช้ได้หรือไม่!

ที่ให้ไว้:

คอลเลกชันชั้นเรียน:

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

คอลเลกชันของนักเรียน:

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

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

person Tony Sepia    schedule 26.12.2016    source แหล่งที่มา


คำตอบ (1)


คุณสามารถใช้:

  • a $group เพื่อจัดกลุ่มตาม class_id และ $push เกรดทั้งหมดในอาร์เรย์ เพื่อให้เราสามารถสรุปอย่างง่ายดายในขั้นตอนถัดไปซึ่งมีคลาส "ประกอบด้วย" blue รักษาเอกสารปัจจุบันด้วย $$ROOT เพราะเราต้องการ นักเรียนที่ตรงกับ class_id

  • a $match เพื่อจับคู่เฉพาะคลาสที่มีเกรด blue อยู่

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

หากคุณต้องการจับคู่สีอื่นนอกเหนือจาก ["สีน้ำเงิน" "สีแดง"] คุณสามารถเพิ่มสีอื่นได้ใน $match aggregation ($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 } }
    }
}
person Bertrand Martel    schedule 26.12.2016