【问题标题】:MongoDB - Mongoose: How Do I Update Simultaneously Two Separate Embedded Documents With Mongoose?MongoDB - Mongoose:如何使用 Mongoose 同时更新两个单独的嵌入式文档?
【发布时间】:2017-06-17 18:19:01
【问题描述】:

所以我试图在一个 API 调用中更新我的 Report 文档和我的 Station.reports 子文档中的字段 status,这是一个对象数组。问题是我可以在进行 API 调用时更新报告文档,但不能更新站文档。调用后,console.log(station.reports); 返回预期的子文档,即:[{"_id":"588fed278b50cd180bd6cc15","date":"2017-01-31T01:48:57.487Z","status":"Archived"}] 但这并没有保存在我的数据库中相应的 Station 文档中。请我在这里需要帮助。谢谢。

站内文件:

{
    "_id": "588a777d4e26720e7afa7e1e",
    "phone": "(007) – 007 – 7007",
    "name": "name1",
    "email": "name1@email.com",
    "reports": [
      {
        "status": "Submitted",
        "date": "2014-01-31T01:48:57.487Z",
        "_id": "588fed278b50cd180bd6cc15"
      }
    ]
}  

报告文件

{
    "_id": "588fed278b50cd180bd6cc15",
    "description": "Description of the report",
    "time": "05:48 PM",
    "date": "2017-01-31T01:48:57.487Z",
    "status": "Archived",
    "location" : "123 Main Street"
    "station" : "588a777d4e26720e7afa7e1e"
}  

API 调用

router.put('/reports/:id/updateStatus', function (req, res) {

    Report.findById(req.params.id, function(err,report){
        // if there is an error retrieving, send the error.
        // nothing after res.send(err) will execute
        if (err)
          return res.send(err);

        //  Update the Report object 
        report.status = req.body.status;

        // Update the Corresponding station.reports subdocument
        Station.findOne({_id:report.station}, function (err, data) {
            if(err) return console.log(err);

            data.reports.forEach(function(rpt){
                if (rpt._id == req.params.id){

                    rpt.status = req.body.status
                    data.save(function (err, station) {
                        if (err)
                            return res.send(err); 

                        console.log(station.reports);
                    })
                }
            })
        })

        report.save(function (err, report) {
            if (err)
                return res.send(err); 

            res.json(report);
        })
    });
})

【问题讨论】:

    标签: javascript node.js mongodb api mongoose


    【解决方案1】:

    经过多次尝试,在 Ravi 的帮助下,我找到了一个非常适合我的解决方案。唯一改变的是我的API 电话。其余代码未更改。
    希望这可以帮助有类似需求的人。

    API 调用

    router.put('/reports/:id/updateStatus', function (req, res) {
    
        Report.findById(req.params.id, function(err,report){
            // if there is an error retrieving, send the error.
            // nothing after res.send(err) will execute
            if (err)
              return res.send(err);
    
            //  Update the Report object 
            report.status = req.body.status;
    
            // Update the Corresponding station.reports subdocument
            Station.findOne({_id:report.station}, function (err, info) {
                if(err) return console.log(err);
    
                info.reports.forEach(function(rpt){
                    if (rpt._id == req.params.id){
    
                        Station.update({_id:info._id, "reports._id":rpt._id },
                            {
                                $set:{"reports.$.status": req.body.status }
                            },function (err, results) {
                                if(err) return console.log("This Station couldn't be updated " + err);
                                console.log(results)
                            }
                        )
                    }
                })
                report.save(function (err, report) {
                    if (err)
                        return res.send(err); 
    
                    res.json({report:report, station:info});
                });
            })
        });
    })
    

    【讨论】:

      【解决方案2】:

      您在更新station 对象时犯了错误。使用findOneAndUpdate找到匹配的Station文档,然后更改匹配的报告项的状态(使用reports._id匹配)。

      试试这个:

      Station.findOneAndUpdate({
              _id:report.station,"reports._id":req.params.id
          },{
              $set : {reports.$.status : req.body.status}
          },function(err){
          if(err)
              return res.send(err);
      });
      

      report._id 将查找_idreq.params.id 的数组元素,report.$.status 将仅更新数组的匹配元素。

      有关positional $(update) operator 的更多信息,请阅读mongoDB positional Documentation

      另外,我建议savecallback of update 中的report 对象。由于nodejsasynchronous,如果您在回调之外保存report,它不会等待update 完成。而且,您可能会收到发送后无法设置标头 error。因此,建议在回调中进行。

      因此您的最终 API 代码如下所示:

      router.put('/reports/:id/updateStatus', function (req, res) {
      
          Report.findById(req.params.id, function(err,report){
              // if there is an error retrieving, send the error.
              // nothing after res.send(err) will execute
              if (err)
                return res.send(err);
      
              //  Update the Report object 
              report.status = req.body.status;
      
              // Update the Corresponding station.reports subdocument
              Station.findOneAndUpdate({
                      "_id":report.station,"reports._id":req.params.id
                  },{
                      $set : {"reports.$.status" : req.body.status}
                  },function(err, result){
                      if(err)
                          return res.send(err);
                      console.log(result);
                      report.save(function (err, report) {
                          if (err)
                              return res.send(err); 
      
                          res.json(report);
                      });
              });
          });
      })
      

      更新 替代方法

      另一种方式可以,你可以按照原来的方式进行,但是不要将数据保存在forEach里面,而是保存数据表forEach完成。

      Station.findOne({_id:report.station}, function (err, data) {
          if(err) return console.log(err);
      
          data.reports.forEach(function(rpt){
              if (rpt._id == req.params.id){
      
                  rpt.status = req.body.status
              }
          });
          data.save(function (err, station) {
              if (err)
                  return res.send(err); 
      
              console.log(station.reports);
              report.save(function (err, report) {
                  if (err)
                      return res.send(err);
                  res.json(report);
              });
          })
      })
      

      希望这会有所帮助!

      【讨论】:

      • 嗨@Ravi。感谢您的回复。我想试试你的建议,但首先考虑到子文档reports 是一个数组,你怎么可能写"reports._id"。这可能会破坏整个事情对吗?也许我错过了什么
      • 不不,你可以这样在数组中查询,reports.$.status只会更新reports数组的匹配元素
      • 真的。我不知道这种技术。好的。让我现在就试试吧。
      • 试过但没用。仍然更新report 对象,但不更新station.reports 子文档。我什至试过$push 而不是$set 运气不好
      • 你能检查是否有错误,但我认为我编辑的答案应该可以工作。
      猜你喜欢
      • 1970-01-01
      • 2011-12-21
      • 2011-12-04
      • 2014-06-12
      • 2023-03-10
      • 2017-01-06
      • 2021-03-26
      • 2017-09-22
      • 1970-01-01
      相关资源
      最近更新 更多