2017-02-01 3 views
0

Итак, я пытаюсь обновить поле status в моем документе Report и в моем подкадре Station.reports, который представляет собой массив объектов, в одном вызове API. Проблема в том, что я могу обновить документ отчета, но не документ станции при вызове API. После вызова console.log(station.reports); возвращает ожидаемый поддокумент, который равен: [{"_id":"588fed278b50cd180bd6cc15","date":"2017-01-31T01:48:57.487Z","status":"Archived"}] Но это не сохраняется в соответствующем документе станции в моей БД. Пожалуйста, мне нужна помощь здесь. Благодарю.Как обновить одновременно два отдельных встроенных документа с помощью Mongoose?

станция Документ:

{ 
    "_id": "588a777d4e26720e7afa7e1e", 
    "phone": "(007) – 007 – 7007", 
    "name": "name1", 
    "email": "[email protected]", 
    "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); 
     }) 
    }); 
}) 

ответ

0

После нескольких попыток, и с помощью Рави, я смог найти решение, которое сработало для меня довольно хорошо. Единственное, что изменилось, это мой звонок 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}); 
      }); 
     }) 
    }); 
}) 
0

Вы делаете ошибку ж hile обновляет объект 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.

Также я бы предложил savereport объект в callback of update. Поскольку nodejs - asynchronous, он не будет ждать завершения 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); 
       }); 
     }); 
    }); 
}) 

UPDATE Альтернативный метод

Другой способ может быть, Вы можете продолжить оригинальным способом, но дон» t сохранить данные внутри 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); 
     }); 
    }) 
}) 

Надеюсь, это поможет!

+0

Привет @Ravi. Спасибо за ваш ответ. Я хотел бы попробовать ваше предложение, но вначале, учитывая, что поддокументы 'reports' являются массивом, как вы можете писать' 'reports._id''. Это, вероятно, полностью нарушит все это? Может быть, я что-то упустил – AllJs

+0

Нет, вы можете запросить в массиве вроде этого, а 'reports. $. Status' будет обновлять только соответствующий элемент массива отчетов. –

+0

Действительно. Я не знал об этой технике. ОК. Позвольте мне попробовать прямо сейчас. – AllJs