首页 > 解决方案 > 匹配主文档和嵌套对象的 id 后更新嵌套对象

问题描述

我有以下结构的 mongo 文档

{
    "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
}

让我告诉你我想在这里做什么。这是我的路线

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

我将_id患者作为:patientID(文档)和_id嵌套检查对象作为传递:examID,我的目标是通过匹配检查 ID 来更新患者的检查。这是我的控制器。

/**
 * 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)
    }
  })
}

我参考了Selecting and update a nested object by it's ObjectId in Mongoose.js。但我收到一个错误。

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

我在做吗?在这种情况下,什么可能是更新单个检查的有效方法。这是仅更新已更改数据的正确方法吗?感谢您花时间阅读本文。

更新[已解决]。我在@thammada.ts 的评论的帮助下修复了它。都是他的功劳。将我的更新更改为:

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
      }
    }
  }

并用于'exam.id'arrayFilters。

标签: node.jsmongodbmongoose

解决方案


你必须改变你的updateoptions如下

/*
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) }]
}

提示:您实际上不必$elemMatch在查询中执行此操作。你可以做

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

或者确保它正在更新正确的患者

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


推荐阅读