node.jsmongodbmongoosemongoose-populate

populate function not working in Node.js and Mongodb


I have two models. One is for Patient and Another one is for Lab Test Report. While inserting a record in Report Model i am getting patient Id by using a common field contactno and storing it in Report model in a field patient which is referring to ObjectId of Patient model.

In Patient model there is a array of reports which on populate should show all reports associate with patient. below are my models and Controllers.

**Patient Model **

const mongoose = require("mongoose")
const Reports = require('./reportModel')

const patientSchema = mongoose.Schema({
name:{
    type:String,
    required:[true,"Please Enter Patient Name"]
},
gender:{
    type:String,
    required:[true, "Please Enter Patient Gender"]
},
age:{
    type:Number,
    required:[true, "Please Enter Patient Age"]
},
address:{
    type:String,
    required:[true, "Please Enter Patient Adress"]
},
dateOfBirth:{
    type:String,
    required:[true, "Please Enter Patient Date of Birth"]
},
email:{
    type:String,
    required:[true, "Please Enter Patient Email"]
},
contact:{
    type:Number,
    required:[true, "Please Enter Patient contact"]
},
reports: [{
  type: mongoose.Schema.ObjectId,
  ref: "Report",
}],
emergContact:{
    type:Number,
    required:[true, "Please Enter Patient Emergency Contact"]
},
weight:{
    type:Number,
    default:1
    },
    reviews: [
        {
          user: {
            type: mongoose.Schema.ObjectId,
            ref: "User",
            required: true,
          },
          name: {
            type: String,
            required: true,
          },
          rating: {
            type: Number,
            required: true,
          },
          comment: {
            type: String,
            required: true,
          },
        },
      ],
    
user: {
        type: mongoose.Schema.ObjectId,
        ref: "User",
        required: true,
      },
createdAt:{
    type:Date,
    default:Date.now
}
})

module.exports = mongoose.model("Patient",patientSchema)

**Reports model **

const mongoose = require("mongoose");
const validator = require("validator");

const reportSchema = mongoose.Schema({
    patient: {
        type: mongoose.Schema.ObjectId,
        ref: "Patient",
        required: true,
      }, 
type:{
    type: String,
    required: [true, "Please Enter Your testType"],
    
},
name:{
    type:String,
    required:[true, "Please enter Type of test"]
},
contact:{
    type:Number,
    required:[true, "Must enter valid contact number of patient"]
},
remarks:{
    type:String,
}


})

module.exports = mongoose.model("Report", reportSchema);

Below is report controller which saves data in report model and also stores Object Id of Patient by querying phone number

exports.createReport = catchAsyncErrors(async(req,res,next)=> {
const patient = await Patient.findOne({contact:req.body.contact})
const newreq = {patient:patient._id,
type:req.body.type,
name:req.body.name,
contact:req.body.contact,
remarks:req.body.remarks
}
const report = await Report.create(newreq)

    res.status(200).json({
        success:true,
        report
        
    })
    }
    
)

Output from report query

{
    "success": true,
    "report": {
        "_id": "652dc1e07acd6e401e4d3da5",
        "patient": "651e3fa49b84a8a8c8532fa1",
        "type": "Skin Test",
        "name": "Skin Examination",
        "contact": 532531216,
        "remarks": "Should use sun block",
        "__v": 0
    }
}

Single Patient query

exports.getPatientDetails = catchAsyncErrors(

    async(req,res,next)=>{
          const patient = await Patient.findById(req.params.id).populate({path:'Report',strictPopulate:false}).exec() 
        
        if(!patient){
            return next(new ErrorHandler("Patient Not Found",404))
        }
        
        res.status(200).json({
            success:true,
            patient
        })
        
        }

)
{
    "success": true,
    "patient": {
        "reports": [],
        "_id": "651e3fa49b84a8a8c8532fa1",
        "name": "Patient 3",
        "gender": "Male",
        "age": 65,
        "address": "Shahdara Lahore",
        "dateOfBirth": "07-05-1945",
        "email": "ptt@gmail.com",
        "contact": 532531216,
        "emergContact": 55666666,
        "weight": 90,
        `"
createdAt": "2023-10-05T04:46:28.810Z",
        "__v": 0,
        "reviews": []
    }
}

reports array is empty whereas according to my understanding it should show array of reports associated with specified patient.

I tried to search online regarding mongodb table joins and population.


Solution

  • Well i am now pasting code of both controllers to be helpful for others. I resolved this issue by making below mentioned changes.

    Report Controller

    exports.createReport = catchAsyncErrors(async (req, res, next) => {
      const patient = await Patient.findOne({ contact: req.body.contact })
      const newreq = {
        patient: patient._id,
        type: req.body.type,
        name: req.body.name,
        contact: req.body.contact,
        remarks: req.body.remarks
      }
        
      const report = await Report.create(newreq)
      newpatient = await Patient.findOneAndUpdate(
        { _id: report.patient },
        { runValidators: false, context: 'query' },
      )
           
      await newpatient.reports.push(report._id)
      await newpatient.save()
      res.status(200).json({
        success: true,
        report        
      })
    })
    

    Patient Controller

    exports.getPatientDetails = catchAsyncErrors(async (req, res, next) => {
      let patient = await Patient.findById(req.params.id).populate(
        { path: 'reports', strictPopulate: false }
      )        
      if (!patient) {
        return next(new ErrorHandler("Patient Not Found",404))
      }
                
      res.status(200).json({
        success: true,
        patient
      })
    })
    

    Now on every new report creation by using contact number it populates ObjectId on both sides and when patient is accessed it also retrieves associated reports.