如何使用Mongoose同时更新两个单独的嵌入式文档?

时间:2017-02-01 05:17:34

标签: javascript node.js mongodb api mongoose

因此,我尝试在一个API调用中更新status文档和我的Report子文档中的字段Station.reports,该子文档是一个对象数组。问题是我能够在进行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);
        })
    });
})

2 个答案:

答案 0 :(得分:0)

更新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.idreport.$.status的数组元素,只会更新数组的匹配元素。

有关positional $(update) operator的详情,请阅读mongoDB positional Documentation

此外,我建议save report callback of update对象。由于nodejsasynchronous,如果您将update保存在回调之外,则不会等待report完成。并且,您可能会在发送 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中,而是将数据表保存为每个完成。

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

希望这有帮助!

答案 1 :(得分:0)

经过多次尝试,并在Ravi的帮助下,我能够找到一个对我有用的解决方案。唯一改变的是我的API电话。其余的代码没有改变  希望这有助于有类似需求的人。

API CALL

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