skip to Main Content

For example, my teacher collection documents look like:

{ _id: new ObjectId("64fee9b54273ac223441225"), teacherid: '64f1d72a4331bc8fc4c5930f', name: 'Jackly' }

and the users collection documents look like:

{ _id: new ObjectId("64f1d72a4331bc8fc4c5930f"), name: 'Mark' }

How can I get the name from users collection by the teacherid in the teacher collection? in MongoDB?

const studentData = await Teacher.aggregate([
    {
        $match: {
            "_id": "64f1d72a4331bc8fc4c5930f"
        }
    },
    {
        $lookup: {
            from: "users",
            localField: "teacherid",
            foreignField: "_id",
            as: "student"
        }
    },
    {
        $unset: "name"
    }
]);

3

Answers


  1. It looks like you’re trying to use the MongoDB aggregation framework to perform a lookup between the "teacher" and "users" collections based on the "teacherid" field. However, there are a few issues with your current aggregation pipeline. Here’s the corrected version of your aggregation query:

    const studentData = await Teacher.aggregate([
        {
            $match: {
                "_id": new ObjectId("64f1d72a4331bc8fc4c5930f") // Convert the ID to ObjectId
            }
        },
        {
            $lookup: {
                from: "users",
                localField: "teacherid",
                foreignField: "_id",
                as: "student"
            }
        },
        {
            $unwind: "$student" // Unwind the "student" array
        },
        {
            $project: {
                "student.name": 1 // Project the "name" field from the "student" subdocument
            }
        }
    ]);
    
    console.log(studentData);
    

    Here’s an explanation of the changes made:

    1. In the $match stage, you need to convert the _id value to an ObjectId using new ObjectId() to match the correct document in the "teacher" collection.

    2. After the $lookup stage, you have an array called "student" that contains the matching user document. To access the "name" field within the "student" subdocument, you need to use the $unwind stage to destructure the array.

    3. Finally, you can use the $project stage to project only the "name" field from the "student" subdocument.

    Now, studentData should contain the "name" field from the "users" collection for the specified teacher ID in the "teacher" collection.

    Login or Signup to reply.
  2. Here is a quick fix solution

    1. change the string id teacherid to a ObjectId
    $ mongo
    
    # replace the `YOUR_DATABASE_NAME` with your real database name.
    > use YOUR_DATABASE_NAME
    
    # update Teacher collection ✅
    > db.Teacher.update(
      {"teacherid" : "64f1d72a4331bc8fc4c5930f"},
      {
        $set: {"teacherid" : ObjectId("64f1d72a4331bc8fc4c5930f")}
      });
    
    
    1. then use teacherid as the match key
    > db.Teacher.aggregate([
        {
            $match: {
                "teacherid": ObjectId("64f1d72a4331bc8fc4c5930f")
            }
        },
        {
            $lookup: {
                from: "user",
                localField: "teacherid",
                foreignField: "_id",
                as: "student"
            }
        },
        {
            $unset: "name"
        }
    ]).pretty();
    
    

    test ✅

    screenshot

    enter image description here

    Login or Signup to reply.
  3. the issue is that the two fields you are trying to compare are of 2 types. One is a string other is ObjectID. I would recommend to have both of them a single type (preferrably ObjectID) when storing so you don’t have to do these intermediate transformations.

    however there are a couple of ways of doing this

    1. Transforming the teacherid to ObjectID and then $lookup. This will however have the teacherid as an ObjectID in the queried result. If you dont want it that way you might have to do an $addFields again and convert back to string
    db.teacher.aggregate([
      { $match: { teacherid: "64f1d72a4331bc8fc4c5930f" } },
      { $addFields: { teacherid: { $toObjectId: "$teacherid" } } },
      { $lookup: { from: "users", localField: "teacherid", foreignField: "_id", as: "student" } },
      { $unset: "name" }
    ])
    

    demo

    1. Transforming the teacherid to ObjectID in the lookup pipeline itself and compairing
    db.teacher.aggregate([
      { $match: { "teacherid": "64f1d72a4331bc8fc4c5930f" } },
      {
        $lookup: {
          from: "users",
          let: { teacherIdStr: "$teacherid" },
          pipeline: [
            {
              $match: {
                $expr: { $eq: [ "$_id", { $toObjectId: "$$teacherIdStr" } ] }
              }
            }
          ],
          as: "student"
        }
      },
      { $unset: "name" }
    ])
    

    demo

    1. Or convert the foreign field ObjectID to string and match
    db.teacher.aggregate([
      { $match: { "teacherid": "64f1d72a4331bc8fc4c5930f" } },
      {
        $lookup: {
          from: "users",
          let: { teacherIdStr: "$teacherid" },
          pipeline: [
            {
              $match: { 
                $expr: { $eq: [ { $toString: "$_id" }, "$$teacherIdStr" ] } 
              }
            }
          ],
          as: "student"
        }
      },
      { $unset: "name" }
    ])
    

    demo

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