matching fields internally in mongodb

旧时模样 提交于 2019-12-04 21:02:14

问题


I am having following document in 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: Not an actual data but schema is exactly same.

Requirement: Finding the document which matches the studentId and students.id(id inside the students array using single query.

I have tried the code like below

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

Result: Empty Array, If i replace {"students.id":"$studentId"} to {"students.id":33} it is returning the second document in the above shown json.

Is it possible to get the documents for this scenario using single query?


回答1:


If possible, I'd suggest that you set the condition while storing the data so that you can do a quick truth check (isInStudentsList). It would be super fast to do that type of query.

Otherwise, there is a relatively complex way of using the Aggregation framework pipeline to do what you want in a single query:

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

Given your input example the output would be:

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

A brief explanation of the steps:

  1. Build a projection of the document with just studentId and a new field with an array containing just the id (so the first document it would contain [23, 55].
  2. Using that structure, $unwind. That creates a new temporary document for each array element in the studentIdComp array.
  3. Now, take those documents, and create a new document projection, which continues to have the studentId and adds a new field called isStudentEqual that compares the equality of two fields, the studentId and studentIdComp. Remember that at this point there is a single temporary document that contains those two fields.
  4. Finally, check that the comparison value isStudentEqual is true and return those documents (which will contain the original document _id and the studentId.
  5. If the student was in the list multiple times, you might need to group the results on studentId or _id to prevent duplicates (but I don't know that you'd need that).



回答2:


Unfortunately it's impossible ;(

to solve this problem it is necessary to use a $where statement (example: Finding embeded document in mongodb?),

but $where is restricted from being used with aggregation framework




回答3:


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



来源:https://stackoverflow.com/questions/16251032/matching-fields-internally-in-mongodb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!