简体   繁体   English

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

[英]MongoDB - Mongoose: How Do I Update Simultaneously Two Separate Embedded Documents With Mongoose?

So I am trying to update the field status in my Report document and in my Station.reports sub-document which is an array of objects, in one single API call. 因此,我试图通过一个API调用来更新Report文档和Station.reports子文档中的字段status ,该子文档是一组对象。 The issue is that I am able to update the Report document, but not the station document when making the API call. 问题是在进行API调用时,我能够更新Report文档,但不能更新Station文档。 After the call, the console.log(station.reports); 通话结束后, console.log(station.reports); returns the expected subdocument which is : [{"_id":"588fed278b50cd180bd6cc15","date":"2017-01-31T01:48:57.487Z","status":"Archived"}] But this is not saved in the corresponding Station document in my DB. 返回期望的子文档: [{"_id":"588fed278b50cd180bd6cc15","date":"2017-01-31T01:48:57.487Z","status":"Archived"}]但这未保存在我的数据库中相应的Station文档。 Please I need help here. 请在这里我需要帮助。 Thanks. 谢谢。

Station Document: 车站文件:

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

Report Document 报告文件

{
    "_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 Call 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);
        })
    });
})

You are doing mistake while updating the station object. 更新station对象时出错。 Use findOneAndUpdate to find the matching Station document, and then change the status of the matched reports item(matched using reports._id). 使用findOneAndUpdate查找匹配的Station文档,然后更改匹配的报告项目(使用reports._id进行匹配)的状态。

Try this: 尝试这个:

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 will find the array element whose _id is req.params.id and report.$.status will update only the matching element of the array. report._id将找到_idreq.params.id的数组元素, report.$.status将仅更新数组的匹配元素。

For more information on positional $(update) operator , Read mongoDB positional Documentation . 有关positional $(update) operator更多信息,请阅读mongoDB位置文档

Also, i would suggest to save the report object in the callback of update . 另外,我建议save report对象savecallback of updatecallback of update As nodejs is asynchronous , it will not wait for the update to finish, if you are saving report outside of the callback. 由于nodejsasynchronous ,因此,如果您将report保存在回调之外,它将不等待update完成。 And, you might get Cant set the headers after they are sent error . 而且,你可能会得到广东话设置的标头发送之后 error Thus, its recommended to do it in the callback. 因此,建议在回调中执行此操作。

Thus your final API code would look like: 因此,您最终的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);
                });
        });
    });
})

UPDATE Alternate Method UPDATE 备用方法

Another way can be, You can proceed in the original way, but don't save the data inside the forEach, instead save the data sheet forEach finishes. 另一种方法是,您可以按原始方式进行操作,但不要将数据保存在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);
        });
    })
})

Hope this helps! 希望这可以帮助!

After multiple attempts, and with the help of Ravi, I was able to figure out a solution that worked for me pretty well. 经过多次尝试,并在Ravi的帮助下,我找到了一个对我来说非常有效的解决方案。 The only thing that changed was my API call. 唯一改变的是我的API调用。 The rest of the code was unchanged. 其余代码未更改。
Hope this helps someone having similar needs. 希望这可以帮助有类似需求的人。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM