Search code examples
mongodbmongooseaggregation-frameworkmongoose-schemamongoose-populate

MongoDb $lookup aggregation returns an empty array


I Have two mongoDB collections one is Jobs and the second one is savedJob, I want to get the job details and which job ID is present on the savedJob collection, But the mongoDb $lookup aggregation returns an empty array.

Firstly, I'm querying the saved job data from the savedJob collection, so I'm querying the saved job document through user ID method id($match) and using this pipeline to get the job details data from the Job collection.

The Query code is

const { userId } = req?.params;

  const pipeline = [
    {
      $match: {
        userId: userId,
      },
    },
    {
      $lookup: {
        from: "Jobs",
        localField: "jobId",
        foreignField: "_id",
        as: "jobDetails",
      },
    },
  ];

  const savedJobsWithJobDetails = await saveJob.aggregate(pipeline);
  console.log(savedJobsWithJobDetails);

The code is working fine in the MongoDB Playground, But in my express server it is returning an empty array, I'm using Mongoose 6.0.1.

The saved job document looks like this:-

enter image description here

and the job's document looks like this:-

enter image description here I checked all the model names and field names, but it's returning an empty array


Solution

  • I think you have a simple typo. Change:

    from: "Jobs" 
    

    to

    from: "jobs"
    

    in your $lookup. (Note the lowercase jobs).

    You also need to convert the jobId from your savejobs schema to an ObjectId because at the minute you are trying to lookup a string when the target id is stored as an ObjectId.

    This can be done with a simple $addFields pipeline step, leveraging the $toObjectId specifically to help you lookup like so:

    const savedJobsWithJobDetails = await saveJob.aggregate([
       {
          $match: {
             userId: userId,
          },
       },
       {
          $addFields: { //< This new pipeline step
             jobIdToLookup: { $toObjectId: "$jobId" }
          },
       },
       {
          $lookup: {
             from: "jobs",
             localField: "jobIdToLookup", //< Now use jobIdToLookup here instead
             foreignField: "_id",
             as: "jobDetails",
          },
       },
       //{   
       //   $project: {
       //      jobIdToLookup: 0  //< Uncomment if you want to suppress this field from the output
       //   }
       //}
     ]).exec();