在 mongodb 中过滤多级数组集合

filtering a multi-level array collection in mongodb

在 mongoDB 中,如何编写过滤 postcodestudent name 和 [=23] 的查询=]subjId 来自这个多级数组?我正在使用 mongoskinExpressJS。这是数据结构

[{
    "_id": "1",
    "postcode": "SE41TB",
    "students": [{
    "name": "ajax",
    "school": "100",
    "age": "7",
    "subjects": [{
        "subjId": "1",
        "subjName": "Maths"
    }, {
        "subjId": "2",
        "subjName": "English"
    }]
    }, {
    "name": "backbone",
    "school": "100",
    "age": "8",
    "subjects": [{
        "subjId": "1",
        "subjName": "Maths"
    }, {
        "subjId": "2",
        "subjName": "English"
    }]
    }]
}, {
    "_id": "2",
    "postcode": "SEI3BT",
    "students": [{
    "name": "jquery",
    "school": "100",
    "age": "7",
    "subjects": [{
        "subjId": "1",
        "subjName": "Maths"
    }, {
        "subjId": "2",
        "subjName": "English"
    }]
    }, {
    "name": "angular",
    "school": "100",
    "age": "8",
    "subjects": [{
        "subjId": "1",
        "subjName": "Maths"
    }, {
        "subjId": "2",
        "subjName": "English"
    }]
    }]
}]

这是我目前所掌握的 student name,但我不知道如何添加 subjId 过滤器 -

    db.collection('test').find({
    'postcode': postcode
}, {
    'students': {
    $elemMatch: {
        'name': name
    }
    }
});

提前致谢。

您可以使用聚合来获得预期结果。

建议避免复杂的嵌套文档结构。

您可以尝试以下聚合查询:

db.collection.aggregate({
    "$match": {
    "postcode": "SE41TB"
    }
}, {
    "$unwind": "$students"
}, {
    "$match": {
    "students.name": "ajax"
    }
}, {
    "$unwind": "$students.subjects"
}, {
    "$match": {
    "students.subjects.subjId": "1"
    }
}, {
    "$group": {
    "_id": {
        "postcode": "$postcode"
    },
    "name": {
        "$first": "$students.name"
    },
    "school": {
        "$first": "$students.school"
    },
    "age": {
        "$first": "$students.age"
    },
    "subjects": {
        "$push": "$students.subjects"
    }
    }
}, {
    "$group": {
    "_id": "$name",
    "students": {
        "$push": {
            "name": "$name",
            "school": "$school",
            "age": "$age",
            "subjects": "$subjects"
        }
    }
    }
})

使用$setDifference and $map可以找到如下匹配结果:

db.collectionName.aggregate({
    "$match": {
        "postcode": "SEI3BT" //match given post code 
    }
}, {
    "$project": {
        "checkStudentsName": {
            "$setDifference": [{
                    "$map": { //$map iterate over students array and first match studentsDetails.name as given name
                        "input": "$students",
                        "as": "studentsDetails",
                        "in": {
                            "$cond": {
                                "if": {
                                    "$eq": ["$$studentsDetails.name", "jquery"]
                                },
                                "then": "$$studentsDetails",
                                "else": false
                            }
                        }
                    }
                },
                [false]
            ]
        }
    }
}, {
    "$unwind": "$checkStudentsName" // this unwind used for unwinding the matched array 
}, {
    "$project": {
        "name": "$checkStudentsName.name",
        "school": "$checkStudentsName.school",
        "age": "$checkStudentsName.age",
        "subjects": "$checkStudentsName.subjects"
    }
}, {
    "$project": {
        "name": 1,
        "school": 1,
        "age": 1,
        "subjects": {
            "$setDifference": [{
                    "$map": { // this $map iterate over subjects array and first match subjectDetails.subjId as given subjId
                        "input": "$subjects",
                        "as": "subjectDetails",
                        "in": {
                            "$cond": {
                                "if": {
                                    "$eq": ["$$subjectDetails.subjId", "1"]
                                },
                                "then": "$$subjectDetails",
                                "else": false
                            }
                        }
                    }
                },
                [false]
            ]
        }
    }
}).pretty()