Я использую Nodejs с MongoDB (мангуст вместе с экспресс).
Поскольку я не доверяю пользовательским данным, мне нужно проверить их из базы данных.
входные данные:
{
"id": "someid",
"nottrusteddata": [ {"id": "1"}, {"id" :"2"}]
}
В моей функции я проверяю данные:
router.post("/validate", (req, res,next) =>{
let validated_data = validate_data(req);
console.info(JSON.stringify(validated_data));
const mydata = new Mydata({
id: req.body.id,
lst : validated_data
});
console.info("mydata: " + JSON.stringify(mydata));
/* Some Usefull stuff is here */
res.status(200).json();
}
function validate_data(req){
let validated_data = []
for(let i = 0; i < req.body.nottrusteddata.length; i++)
{
Databaseobject.findOne({'id': req.body.nottrusteddata[i].id})
.exec()
.then(dbobject =>{
if (dbobject) // not undefined, it exists in the database
{
// Some logic with the object returned from the database
let tmp_object = {};
tmpobject.id = dbobject.id;
// Append it to the list, so that the upper function can use it
validated_data.push(tmp_object);
}
})
}
return validated_data;
}
Желаемый вывод должен содержать правильную информацию, поступающую из базы данных, однако из-за асинхронной природы nodejs validated_data возвращает значение null.
Я также пытался использовать Promise. У меня не получилось.
const validate_data = function(req){
return new Promise(function(resolve,reject){
let validated_data = []
for(let i = 0; i < req.body.nottrusteddata.length; i++)
{
Databaseobject.findOne({'id': req.body.nottrusteddata[i].id})
.exec()
.then(dbobject =>{
if (dbobject) // not undefined, it exists in the database
{
let tmp_object = {};
tmpobject.id = dbobject.id;
validated_data.push(tmp_object);
}
})
}
resolve(validated_data);
}
}
Что я делаю неправильно? Как я могу дождаться завершения запроса к базе данных, а затем выполнить основную часть? Если бы была только одна проверка, я мог бы использовать .then(). Однако список мог содержать много элементов, и мне нужно дождаться их проверки.





Ваши вызовы Databaseobject.findOne() являются асинхронными, поэтому ваше обещание будет разрешено до того, как любой из них завершится.
Вы можете использовать Promise.all, чтобы дождаться выполнения всех ваших промисов.
Надеюсь, это сработает для вас:
router.post("/validate", (req, res) => {
validate_data(req.body.nottrusteddata)
.then(validated_data => {
const mydata = new Mydata({
id: req.body.id,
lst: validated_data
})
// Some useful stuff is here
res.status(200).json()
})
.catch(err => {
// Handle error
})
}
function validate_data(nottrusteddata) {
// Create array of pending promises
const promises = nottrusteddata
.map(item => {
return Databaseobject
.findOne({ 'id': item.id })
.exec()
})
// Wait for all promises to resolve
return Promise.all(promises)
.then(docs => {
return docs
.filter(dbobject => dbobject) // Filter out undefined
.map(dbobject => {
return { id: dbobject.id }
})
})
}
Если хотите, вы также можете использовать здесь асинхронное ожидание:
router.post("/validate", async (req, res) => {
try {
const validated_data = await validate_data(req.body.nottrusteddata)
const mydata = new Mydata({
id: req.body.id,
lst: validated_data
})
// Some useful stuff is here
res.status(200).json()
}
catch(err) {
// Handle error
}
})
Если вызовы db не должны быть последовательными, вы можете снова использовать Promise.all(), чтобы запустить их все сразу.
Я не мог выполнить асинхронное ожидание. Просто не дождется. Тем не менее, я ждал, пока все обещания будут выполнены. Асинхронная функция была бы лучше, потому что у меня сложные данные, и каждую часть данных нужно проверять из разных коллекций базы данных. Прямо сейчас я делаю это, и это нормально, но это можно улучшить:
check1().then(firstinfo =>{ check2().then(secondinfo =>{...})})Или мне нужно найти способ дождаться нескольких проверок базы данных, а не выполнять предложенияexec.then.