9

我在 mongodb 中有以下文档

    {
        "_id" : ObjectId("517b88decd483543a8bdd95b"),
        "studentId" : 23,
        "students" : [
          {
           "id" : 23,
           "class" : "a"
           },
          {
           "id" : 55,
           "class" : "b"
           }
        ]
     }
     {
        "_id" : ObjectId("517b9d05254e385a07fc4e71"),
        "studentId" : 55,
        "students" : [
           {
            "id" : 33,
            "class" : "c"
          }
         ]
     }

Note:不是实际数据,但架构完全相同。

Requirement:使用单个查询studentId在学生数组中查找与and students.id(id匹配的文档。

我已经尝试过如下代码

db.data.aggregate({$match:{"students.id":"$studentId"}},{$group:{_id:"$student"}});

Result:空数组,如果我将 {"students.id":"$studentId"} 替换为 {"students.id":33} 它会返回上面显示的 json 中的第二个文档。

是否可以使用单个查询获取此场景的文档?

4

3 回答 3

13

如果可能的话,我建议您在存储数据时设置条件,以便您可以快速进行真实性检查 ( isInStudentsList)。执行这种类型的查询会非常快。

否则,有一种相对复杂的方法可以使用聚合框架管道在单个查询中执行您想要的操作:

db.students.aggregate( 
    {$project: 
        {studentId: 1, studentIdComp: "$students.id"}},  
    {$unwind: "$studentIdComp"}, 
    {$project : { studentId : 1, 
        isStudentEqual: { $eq : [ "$studentId", "$studentIdComp" ] }}}, 
    {$match: {isStudentEqual: true}})

给定您的输入示例,输出将是:

{
    "result" : [
         {
             "_id" : ObjectId("517b88decd483543a8bdd95b"),
             "studentId" : 23,
             "isStudentEqual" : true
         }
    ],
    "ok" : 1
}

步骤的简要说明:

  1. 使用 just 和一个新字段构建文档的投影,该studentId字段的数组仅包含id(因此它将包含的第一个文档[23, 55].
  2. 使用该结构,$unwind。这将为数组中的每个数组元素创建一个新的临时文档studentIdComp
  3. 现在,获取这些文档,并创建一个新的文档投影,它继续具有studentId并添加一个名为的新字段isStudentEqual,用于比较两个字段的相等性studentIdstudentIdComp。请记住,此时有一个包含这两个字段的临时文档。
  4. 最后,检查比较值isStudentEqual是否为真并返回那些文档(其中将包含原始文档_idstudentId.
  5. 如果学生多次出现在列表中,您可能需要将结果分组studentId_id防止重复(但我不知道您是否需要)。
于 2013-04-27T13:43:22.437 回答
0

不幸的是这是不可能的;(

要解决这个问题,需要使用$where语句(例如:在 mongodb 中查找嵌入文档?),

但是$where限制与聚合框架一起使用

于 2013-04-27T10:51:01.793 回答
-1

db.data.find({students: {$elemMatch: {id: 23}} , studentId: 23});

于 2013-04-27T10:48:37.380 回答