У меня есть конечная точка исправления, которая обновляет тело полей, выполняет итерацию по каждому полю и обновляет правильное значение. Я хочу что-то сделать, отправить ответ, как только все это будет сделано, но я не знаю, как дождаться цикла операций. Если бы это была единственная операция, я мог бы просто добавить .then(), но в данном случае это не сработало бы. Какое элегантное решение для этого?
Код:
const updateUser = (req, res) => {
const db = mongoConnection.getDb();
for (key in req.body) {
db.collection('users').updateOne(
{username: req.query.username},
{$set: {[key]: req.body[key]}}
)
}
// send response once for loop is done
}
Я думаю, что простым ответом было бы скрыть цикл for в асинхронной функции, а затем использовать его в конечной точке.
const updateUserField = async () =>
db.collection("users").updateOne(
{
username: req.query.username,
},
{
$set: { [key]: req.body[key] },
}
);
const updateUserEndpoint = (req, res) => {
for (let field of req.body) {
await updateUserField(field);
}
res.status(200).send('updated');
}
Затем для тестирования вы можете обернуть конечную точку функцией, которая внедряет саму функцию:
const updateUserEndpoint = (userUpdateFunc) => userUpdateFunc(req, res);
Этот паттерн называется внедрением зависимостей — при написании модульных тестов для конечной точки вы просто замените userUpdateFunc
любой фиктивной функцией, которую хотите использовать. Это избавляет от необходимости исправлять функцию в тесте.
Вы забыли отметить updateUserEndpoint
как async
. Также внутри updateUserField
вы не возвращаете обновление БД, так что на самом деле ждать нечего. Функция также не использует аргумент поля. Это решение, как оно есть, не работает. Лучшее решение — запускать обновления параллельно, как указано в моем ответе ниже.
Вы можете пометить внешнюю функцию async
и await
каждое обновление БД внутри цикла. Тогда вы узнаете, что после завершения цикла все обновления БД выполняются.
Еще лучше запускать обновления параллельно, так как они не зависят друг от друга. Вы можете использовать Promise.allSettled()
, который принимает массив обещаний и разрешается, когда завершается последнее.
const updateUser = async (req, res) => {
const db = mongoConnection.getDb();
const dbUpdates = Object.entries(req.body).map((key, value) => {
return db.collection('users').updateOne(
{ username: req.query.username },
{ $set: { [key]: value }}
);
});
await Promise.allSettled(dbUpdates);
// Send response, at this point all DB updates are done
};
Функция
updateUserField()
избыточна, так какupdateOne()
уже возвращает обещание. ТакжеupdateUserField
- это() => {}
, который не принимает аргументов, но вы называете егоupdateUserField(field)
, он должен быть либоupdateUserField()
(удалитьfield
), либоupdateUserField = (field) => {}