skip to Main Content

I have a studentsubject schema.
Properties are subject_id,student_id,class_id

So my usecase is i want to find the one student where class_id, student_id matches. Subject id is optional. Means if subject id is present with that student and class id , then pick that student where all 3 id : class id,student id and subject id matches (because it is priority). Else pick the student where student id and class id matches, subject id might be different.

Ps: there might be multiple documents with same class id and student id. If we include subject id then it identify one document.

I tried this one

studentsubject.findone({
    student_id: studentId,
    class_id : classId,
    $or:[
        {
            subject_id : subjectId
        },
        {
            subject_id : {$exists:true}
        }
    ]
})

It fetches the first matched document where class id and student id matches, not looking for existing data where subject id matches

2

Answers


  1. The simplest solution would be to use a JS script. This one should work for your example:

    db = db.getSiblingDB('YOURDB');
    
    const results = db.studentsubject.findOne({ student_id: studentId, class_id: classId, subject_id: subjectId });
    
    if (results) {
      print(results);
    } else {
      print(db.events.findOne({ student_id: studentId, class_id: classId, subject_id: { $exists: true } }));
    }
    
    

    Then you can run this script by using load('path/to/script.js'). Obviously, you need to provide the values, because in this script studentId, classId and subjectId are undefined.

    Login or Signup to reply.
  2. It fetches the first matched document where class id and student id matches, not looking for existing data where subject id matches

    Its because you are giving an or statement subject_id : {$exists:true}. your query states:

    Match student_id, match class_id, and match subject_id

    OR

    Match student_id, match class_id, and just check if the document is assigned a subject_id irrespective of its value

    Solution

    Just remove subject_id : {$exists:true}. Your query should look like this:

    db.demo.findOne({
        student_id: "1",
        class_id : "A",
        subject_id : "English"
    })
    

    Explanation

    Lets take this sample data:

    [
      {
        "student_id": "1",
        "class_id": "A",
        "subject_id": "Math",
        "student_name": "Tony"
      },
      {
        "student_id": "2",
        "class_id": "B",
        "subject_id": "English",
        "student_name": "Natasha"
      },
      {
        "student_id": "1",
        "class_id": "A",
        "subject_id": "Science",
        "student_name": "Tony"
      }
    ]
    

    Let this be your query:

    db.demo.findOne({
        student_id: "1",
        class_id : "A",
        $or:[
            {
                subject_id : "English"
            },
            {
                subject_id : {$exists:true}
            }
        ]
    })
    

    This will check for student_id: 1, class_id: A, and subject_id: English OR student_id: 1, class_id: A, and if there is any subject_id assigned. So it iterates through the document and stumbles upon this first:

    {
        "student_id": "1",
        "class_id": "A",
        "subject_id": "Math",
        "student_name": "Tony"
    }
    

    The student_id and class_id matches, and subject_id : {$exists:true} as a subject_id does exist there, hence returning this document.

    So modify your query to this:

    db.demo.findOne({
        student_id: "1",
        class_id : "A",
        subject_id : "English"
    })
    

    This will check if all three matches, and don’t worry if a document doesn’t have subject_id field, the query will skip it as it doesn’t meet all the requirements.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search