2

I have a following structure of mongo document

{
    "registrationDate": "2020-06-09T18:15:00.000Z",
    "_id": "5ee6dd003a97c93c6436349c",
    "ofSite": "5ee19fe085d70733243c3309",
    "patientID": "NGH-123",
    "neocareID": "",
    "babyName": "Joey",
    "motherName": "Phoebe",
    "dateOfBirth": "2020-06-08T18:15:00.000Z",
    "babySex": "Female",
    "birthType": "Single",
    "patientType": "Referred",
    "mobileNumber": "9802824412",
    "mobileOf": "Family Member",
    "linkedFCHV": "Racheal",
    "FCHVmobile": "9876225420",
    "address": "Holloywood",
    "examinations": [
        {
            "ODExam": {
                "plusODExam": "No",
                "zoneODExam": "I",
                "ropODExam": "No",
                "ropODStage": 1,
                "categoryOD": "None",
                "apROPOD": "Yes"
            },
            "OSExam": {
                "plusOSExam": "No",
                "zoneOSExam": "I",
                "ropOSExam": "Yes",
                "ropOSStage": 1,
                "categoryOS": "None",
                "apROPOS": "Yes"
            },
            "FindingFollowUp": {
                "ropFindings": "All Good so far",
                "followUpPlan": "Follow up in next month",
                "nameOfExaminer": "Luzan",
                "followUpDate": "2020-07-07T18:15:00.000Z"
            },
            "_id": "5ee6dd793a97c93c6436349e",
            "examinationDate": "06/12/2020",
            "currentPMA": 5,
            "daysOfLife": 42,
            "currentWeight": 4500,
            "visitType": "First"
        },
        {
            "ODExam": {
                "plusODExam": "No",
                "zoneODExam": "I",
                "ropODExam": "No",
                "ropODStage": 1,
                "categoryOD": "None",
                "apROPOD": "Yes"
            },
            "OSExam": {
                "plusOSExam": "No",
                "zoneOSExam": "I",
                "ropOSExam": "Yes",
                "ropOSStage": 1,
                "categoryOS": "None",
                "apROPOS": "Yes"
            },
            "FindingFollowUp": {
                "ropFindings": "All Good so far",
                "followUpPlan": "Follow up in next month",
                "nameOfExaminer": "Luzan",
                "followUpDate": "2020-07-07T18:15:00.000Z"
            },
            "_id": "5ee6dd913a97c93c643634a0",
            "examinationDate": "06/12/2020",
            "currentPMA": 5,
            "currentWeight": 4500,
            "visitType": "First"
        },
        {
            "ODExam": {
                "plusODExam": "No",
                "zoneODExam": "I",
                "ropODExam": "No",
                "ropODStage": 1,
                "categoryOD": "None",
                "apROPOD": "Yes"
            },
            "OSExam": {
                "plusOSExam": "No",
                "zoneOSExam": "I",
                "ropOSExam": "Yes",
                "ropOSStage": 1,
                "categoryOS": "None",
                "apROPOS": "Yes"
            },
            "FindingFollowUp": {
                "ropFindings": "All Good so far",
                "followUpPlan": "Follow up in next month",
                "nameOfExaminer": "Luzan",
                "followUpDate": "2020-07-07T18:15:00.000Z"
            },
            "_id": "5ee6ddf13a97c93c643634a2",
            "examinationDate": "06/12/2020",
            "currentPMA": 5,
            "currentWeight": 4500,
            "visitType": "First"
        },
        {
            "ODExam": {
                "plusODExam": "No",
                "zoneODExam": "I",
                "ropODExam": "No",
                "ropODStage": 1,
                "categoryOD": "None",
                "apROPOD": "Yes"
            },
            "OSExam": {
                "plusOSExam": "No",
                "zoneOSExam": "I",
                "ropOSExam": "Yes",
                "ropOSStage": 1,
                "categoryOS": "None",
                "apROPOS": "Yes"
            },
            "FindingFollowUp": {
                "ropFindings": "All Good so far",
                "followUpPlan": "Follow up in next month",
                "nameOfExaminer": "Luzan",
                "followUpDate": "2020-07-07T18:15:00.000Z"
            },
            "_id": "5ee6de093a97c93c643634a4",
            "examinationDate": "06/12/2020",
            "currentPMA": 5,
            "currentWeight": 4500,
            "visitType": "First"
        }
    ],
    "__v": 4
}

Let me tell you what I am trying to do here. This is my route

adminRoutes.post(
  '/examination/:patientID/:examID',
  userController.ensureAuthenticated,
  examController.findOneAndUpdate
)

I am passing _id of patient as :patientID (document) and _id of nested examinations object as :examID, my objective is to update the examination of patient by matching examination id. This is my controller.

/**
 * POST /admin/examination/:patientID/:examID
 **/
exports.findOneAndUpdate = function (req, res) {
  const query = { examinations: { $elemMatch: { _id: new ObjectId(req.params.examID) } } }
  const update = {
    $set: {
      examinationDate: req.body.examinationDate,
      daysOfLife: req.body.daysOfLife,
      currentPMA: req.body.currentPMA,
      currentWeight: req.body.currentWeight,
      visitType: req.body.visitType,
      ODExam: {
        plusODExam: req.body.plusODExam,
        zoneODExam: req.body.zoneODExam,
        ropODExam: req.body.ropODExam,
        ropODStage: req.body.ropODStage,
        categoryOD: req.body.categoryOD,
        apROPOD: req.body.apROPOD
      },
      OSExam: {
        plusOSExam: req.body.ropOSExam,
        zoneOSExam: req.body.zoneOSExam,
        ropOSExam: req.body.ropOSExam,
        ropOSStage: req.body.ropOSStage,
        categoryOS: req.body.categoryOS,
        apROPOS: req.body.apROPOS
      },
      FindingFollowUp: {
        ropFindings: req.body.ropFindings,
        followUpPlan: req.body.followUpPlan,
        nameOfExaminer: req.body.nameOfExaminer,
        followUpDate: req.body.followUpDate
      }
    }
  }
  const options = { arrayFilters: [{ 'examinations._id': new ObjectId(req.params.examID) }] }
  Patient.updateOne(query, update, options, function (err, result) {
    if (err) {
      console.log(err)
      res.send(err)
    } else {
      console.log(result)
      res.send(result)
    }
  })
}

I took reference from Selecting and updating a nested object by it's ObjectId in Mongoose.js. But I am getting an error.

MongoError: The array filter for identifier 'examinations' was not used in the update { $set: { daysOfLife: 45 } }

Am I doing it worng, what might be an effective way to update a single examination in this case. And is this a proper way to update only the data what has been changed? Thank you for your time reading this.

Update [Solved]. I fixed it with the help of comment from @thammada.ts . All thanks to him. Changed my update as:

const update = {
    $set: {
      'examinations.$[exam].examinationDate': req.body.examinationDate,
      'examinations.$[exam].daysOfLife': req.body.daysOfLife,
      'examinations.$[exam].currentPMA': req.body.currentPMA,
      'examinations.$[exam].currentWeight': req.body.currentWeight,
      'examinations.$[exam].visitType': req.body.visitType,
      'examinations.$[exam].ODExam': {
        plusODExam: req.body.plusODExam,
        zoneODExam: req.body.zoneODExam,
        ropODExam: req.body.ropODExam,
        ropODStage: req.body.ropODStage,
        categoryOD: req.body.categoryOD,
        apROPOD: req.body.apROPOD
      },
      'examinations.$[exam].OSExam': {
        plusOSExam: req.body.ropOSExam,
        zoneOSExam: req.body.zoneOSExam,
        ropOSExam: req.body.ropOSExam,
        ropOSStage: req.body.ropOSStage,
        categoryOS: req.body.categoryOS,
        apROPOS: req.body.apROPOS
      },
      'examinations.$[exam].FindingFollowUp': {
        ropFindings: req.body.ropFindings,
        followUpPlan: req.body.followUpPlan,
        nameOfExaminer: req.body.nameOfExaminer,
        followUpDate: req.body.followUpDate
      }
    }
  }

and used 'exam.id' on arrayFilters.

4
  • 1
    If you are using examinations in your arrayFilters, you will have to specify examinations[examinations] in your update. Maybe you should rename to examinations[exam] and exam._id to avoid confusion Commented Jun 20, 2020 at 10:18
  • @thammada.ts thanks for your time, can you please share me how I should do it. Commented Jun 20, 2020 at 10:24
  • @thammada.ts I got it. Thanks so much. Commented Jun 20, 2020 at 10:53
  • I have posted an answer nonetheless, I didn't see your update on the question :). Also added some tips on the query part Commented Jun 20, 2020 at 11:06

1 Answer 1

1

You have to change your update and options as follows

/*
Keep in mind that this will replace the whole element,
if you have other fields not included in the update, they will be removed.
To update new fields without replacing the element,
you have to specify all the fields like this

{
  $set: {
...
    "examinations.$[exam].examinationDate": req.body.examinationDate,
    "examinations.$[exam].daysOfLife": req.body.daysOfLife,

...
    "examinations.$[exam].ODExam.plusODExam": req.body.plusODExam,
    "examinations.$[exam].ODExam.zoneODExam": req.body.zoneODExam
...
  }
}
*/
const update = {
  $set: {
    "examinations.$[exam]": {
      _id: new ObjectId(req.params.examID),
      examinationDate: req.body.examinationDate,
      daysOfLife: req.body.daysOfLife,
      currentPMA: req.body.currentPMA,
      currentWeight: req.body.currentWeight,
      visitType: req.body.visitType,
      ODExam: {
        plusODExam: req.body.plusODExam,
        zoneODExam: req.body.zoneODExam,
        ropODExam: req.body.ropODExam,
        ropODStage: req.body.ropODStage,
        categoryOD: req.body.categoryOD,
        apROPOD: req.body.apROPOD
      },
      OSExam: {
        plusOSExam: req.body.ropOSExam,
        zoneOSExam: req.body.zoneOSExam,
        ropOSExam: req.body.ropOSExam,
        ropOSStage: req.body.ropOSStage,
        categoryOS: req.body.categoryOS,
        apROPOS: req.body.apROPOS
      },
      FindingFollowUp: {
        ropFindings: req.body.ropFindings,
        followUpPlan: req.body.followUpPlan,
        nameOfExaminer: req.body.nameOfExaminer,
        followUpDate: req.body.followUpDate
      }
    }
  }
}
const options = {
  arrayFilters: [{ 'exam._id': new ObjectId(req.params.examID) }]
}

Tip: you don't really have to do $elemMatch in your query. You can do

const query = { "examinations._id": new ObjectId(req.params.examID) }

Or to make sure it's updating the correct patient

const query = {
  "_id": new ObjectId(req.params.patientID),
  "examinations._id": new ObjectId(req.params.examID)
}

Sign up to request clarification or add additional context in comments.

2 Comments

I am not sure why but following this answer, the _id of examination was changed.
Oh, because we are pushing a whole new document, see my explanation in the comment at the beginning of the code. I'll add the same _id back

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.