首页 文章

MongoDB:如何确定数组字段是否包含元素?

提问于
浏览
58

我有两个系列 . 第一个系列包含学生:

{ "_id" : ObjectId("51780f796ec4051a536015cf"), "name" : "John" }
{ "_id" : ObjectId("51780f796ec4051a536015d0"), "name" : "Sam" }
{ "_id" : ObjectId("51780f796ec4051a536015d1"), "name" : "Chris" }
{ "_id" : ObjectId("51780f796ec4051a536015d2"), "name" : "Joe" }

第二个系列包含课程:

{
        "_id" : ObjectId("51780fb5c9c41825e3e21fc4"),
        "name" : "CS 101",
        "students" : [
                ObjectId("51780f796ec4051a536015cf"),
                ObjectId("51780f796ec4051a536015d0"),
                ObjectId("51780f796ec4051a536015d2")
        ]
}
{
        "_id" : ObjectId("51780fb5c9c41825e3e21fc5"),
        "name" : "Literature",
        "students" : [
                ObjectId("51780f796ec4051a536015d0"),
                ObjectId("51780f796ec4051a536015d0"),
                ObjectId("51780f796ec4051a536015d2")
        ]
}
{
        "_id" : ObjectId("51780fb5c9c41825e3e21fc6"),
        "name" : "Physics",
        "students" : [
                ObjectId("51780f796ec4051a536015cf"),
                ObjectId("51780f796ec4051a536015d0")
        ]
}

每个课程文档都包含 students 数组,其中包含为该课程注册的学生列表 . 当学生在网页上查看课程时,他需要查看他是否已经注册了该课程 . 为了做到这一点,当代表学生查询 courses 集合时,我们需要找出 students 数组是否已包含学生的ObjectId . 有没有办法在find查询的投影中指定从 students 数组中检索学生 ObjectId 只有在那里?

我试图看看我是否可以使用$ elemMatch运算符,但它适用于一系列子文档 . 我知道我可以使用聚合框架,但似乎在这种情况下它会过度杀戮 . 聚合框架可能没有单个查找查询那么快 . 有没有办法查询课程集合,以便返回的文档可以采用与此类似的形式?

{
        "_id" : ObjectId("51780fb5c9c41825e3e21fc4"),
        "name" : "CS 101",
        "students" : [
                ObjectId("51780f796ec4051a536015d0"),
        ]
}

2 回答

  • 19

    [ edit 基于此现在可以在最近的版本]

    [更新的答案]您可以通过以下方式查询,只有在已经注册的情况下才能获取课程名称和学生ID .

    db.student.find({},
     {_id:0, name:1, students:{$elemMatch:{$eq:ObjectId("51780f796ec4051a536015cf")}}})
    

    你会得到你期望的回报:

    { "name" : "CS 101", "students" : [ ObjectId("51780f796ec4051a536015cf") ] }
    { "name" : "Literature" }
    { "name" : "Physics", "students" : [ ObjectId("51780f796ec4051a536015cf") ] }
    

    [原始答案]它's not possible to do what you want to do currently. This is unfortunate because you would be able to do this if the student was stored in the array as an object. In fact, I' ma有点惊讶你只使用ObjectId()因为如果你想要显示在特定课程中注册的学生列表,总是要求你查找学生(查看Id的第一个然后查看列表学生集合中的名字 - 两个查询而不是一个!)

    如果您在课程数组中存储(作为示例)Id和名称,如下所示:

    {
            "_id" : ObjectId("51780fb5c9c41825e3e21fc6"),
            "name" : "Physics",
            "students" : [
                    {id: ObjectId("51780f796ec4051a536015cf"), name: "John"},
                    {id: ObjectId("51780f796ec4051a536015d0"), name: "Sam"}
            ]
    }
    

    那么你的查询就是:

    db.course.find( { }, 
                    { students : 
                        { $elemMatch : 
                           { id : ObjectId("51780f796ec4051a536015d0"), 
                             name : "Sam" 
                           } 
                        } 
                    } 
    );
    

    如果那个学生只注册了CS 101,你就会回来:

    { "name" : "Literature" }
    { "name" : "Physics" }
    {
        "name" : "CS 101",
        "students" : [
            {
                "id" : ObjectId("51780f796ec4051a536015cf"),
                "name" : "John"
            }
        ]
    }
    
  • 58

    似乎$in运算符可以很好地满足您的目的 .

    你可以这样做(伪查询):

    if (db.courses.find({"students" : {"$in" : [studentId]}, "course" : courseId }).count() > 0) {
      // student is enrolled in class
    }
    

    或者,您可以删除 "course" : courseId 子句并返回学生注册的所有课程的集合 .

相关问题