SailsJS / Waterline ORM: обновить несколько записей, используя только один запрос - PullRequest
0 голосов
/ 17 апреля 2019

В настоящее время я использую инфраструктуру SailsJS и пытаюсь обновить массив элементов, используя только один запрос в моей базе данных MongoDB.

Вот что я делаю, но записи не обновляются ..

Входящий JSON:

{
  "cars": [
    {
      "id": "5cb5cbd5c395a01b4c9d86da",
      "latitude": "-5",
      "longitude": "551"
    },
    {
      "id": "5cb5cbd7c395a01b4c9d86db",
      "latitude": "-4",
      "longitude": "4421",
    }
  ]
}

Контроллер:

async setLocationOfCars(req, res) {

    try {

        sails.log.info(controllerName + "::" + req.options.action + "() - called");

        const carsLocationArray = req.body.cars;

        let response = CarService.setLocationOfCars(carsLocationArray);
        switch (response.status) {
            case constants.RESOURCE_SUCCESSFULLY_UPDATED :
                return HttpResponseService.json(200, res, constants.RESOURCE_SUCCESSFULLY_UPDATED, response.data);
            default:
                return HttpResponseService.internalServerError(res, response);
        }

    } catch(err) {
        return HttpResponseService.internalServerError(res, err);
    }

}

Услуги:

async setLocationOfCars(cars) {

    try {

        const arrayOfIdsUpdated = [];
        _.forEach(cars, async function(car){

            let attributesToUpdate = {};
            if (car.hasOwnProperty("latitude")) {
                attributesToUpdate.latitude = car.latitude;
            }
            if (car.hasOwnProperty("longitude")) {
                attributesToUpdate.longitude = car.longitude;
            }

            await Car.updateOne({
                id: car.id
            }).set(attributesToUpdate);

            arrayOfIdsUpdated.push(gateway.id)

        });

        return {
            status: constants.RESOURCE_SUCCESSFULLY_UPDATED,
            data  : arrayOfIdsUpdated
        };

    } catch (err) {
        return {
            status : constants.DATABASE_ERROR,
            name   : err.name ? err.name      : "",
            message: err.message ? err.message: "",
            stack  : err.stack ? err.stack    : "",
            code   : err.code ? err.code      : "",
        };
    }

}

1 Ответ

1 голос
/ 17 апреля 2019

В вашем контроллере

Убедитесь, что вы await получаете ответ от вашего сервиса.

let response = await CarService.setLocationOfCars(carsLocationArray);

В вашем "сервисе"

Я бы, наверное,замените _.forEach обычным циклом for.В вашем случае что-то вроде следующего, гарантирующее, что gateway.id действительно определено и значение, которое вы хотите вернуть к вызывающему коду (в вашем вопросе нет ссылки на gateway).

for (let car of cars) {
  let attributesToUpdate = {};
  if (car.hasOwnProperty("latitude")) {
    attributesToUpdate.latitude = car.latitude;
  }
  if (car.hasOwnProperty("longitude")) {
    attributesToUpdate.longitude = car.longitude;
  }

  await Car.updateOne({
    id: car.id
  }).set(attributesToUpdate);


  // Where does gateway.id come from?
  arrayOfIdsUpdated.push(gateway.id)
}

Тосказал, что это будет выполнять cars.length количество запросов к базе данных, а не "используя только один запрос".

Но почему бы не _.forEach?

Использование обратного вызова async внутри forEach, как нене похоже, что он будет делать то, что вы, вероятно, хотите, чтобы он делал.Вполне вероятно, что ваш arrayOfIdsUpdated будет возвращен вашему коду контроллера пустым, за до любого из вызовов updateOne run.

Возьмем, к примеру,

const _ = require('lodash');

function doNothing() {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, 0)
  });
}

var foos = [1, 2, 3, 4, 5, 6]
_.forEach(foos, async (foo) => {
  await doNothing();
  console.log(`Finished #${foo}`);
});


console.log('Done!')

При запуске он выдает

Done!
Finished #1
Finished #2
Finished #3
Finished #4
Finished #5
Finished #6

Обратите внимание, как «Готово!»регистрируется в консоли перед тем, как await отправит ответ в обратный вызов forEach.

...