Async Problem Array leer Nodejs Mungo
Ich möchte aus einer Reihe von IDs, die in der req.body enthalten sind, den Namen und den Preis jedes der Produkte erhalten und in einem neuen Modell speichern (Zahlung). Dazu gehe ich jedes Produkt durch und suche nach seiner ID in der db (Product.findById) und ich speichern als Objekt in arrayProducts, was ich brauche (Name und Preis), aber die neue Zahlung wird erstellt, bevor die arrayProducts vollständig gefüllt sind, und ich erstelle sie leer, da ich dies tun könnte, damit die neue Zahlung erstellt wird nach dem forEach der Produkte fertig?
router.post('/new/payment', async (req, res) => {
const date = Date.now();
const { amount, clientId, products, services, officeId } = req.body;
var arrayProducts = [];
products.forEach(function (product) {
var productFound = {};
Product.findById(product, function (err, result) {
if (err) {
res.status(404).send({ error: "Oh uh, something went wrong", err: err });
}
else {
productFound = { name: result.name, price: result.price };
arrayProducts.push(productFound);
console.log(arrayProducts);
}
})
});
console.log(arrayProducts);
const newPayment = new Payment({ amount, clientId, products: arrayProducts, services, officeId, date });
await newPayment.save((err) => {
if (err) {
res.status(404).send({ error: "Oh uh, something went wrong", err: err });
}
else {
res.status(201).send({ status: "Payment successful", id: newPayment._id });
}
});;
});
Antworten
Sie müssen etwas über nicht blockierende asynchrone Operationen in node.js lesen. Ihr Product.findById()ist nicht blockierend und asynchron, was bedeutet, dass sein Rückruf LONG heißt, nachdem Ihr gesamter Routenhandler die Ausführung abgeschlossen hat, und sicherlich nach dem console.log(arrayProducts);und dem gesamten Code, der danach kommt.
Da Sie N Anforderungen aus Ihrer Datenbank ausführen möchten und nur wissen möchten, wann alle Anforderungen erfüllt sind, können Sie am effizientesten die Promise-Schnittstelle für Ihre Datenbank verwenden und eine Reihe von Versprechungen aus allen DB-Vorgängen erfassen und dann verwenden Promise.all(), um zu informieren, wenn alle fertig sind.
Folgendes würde ich vorschlagen:
router.post('/new/payment', async (req, res) => {
const date = Date.now();
const { amount, clientId, products, services, officeId } = req.body;
try {
const allProducts = await Promise.all(products.map(async (product) => {
const item = await Product.findById(product);
return {name: item.name, price: item.price};
}));
const newPayment = new Payment({ amount, clientId, products: allProducts, services, officeId, date });
await newPayment.save();
res.status(201).send({ status: "Payment successful", id: newPayment._id });
} catch(err) {
res.status(404).send({ error: "Oh uh, something went wrong", err: err });
}
});
Andere Dinge, die in diesem Code fehlen, sind:
- Überprüfen der Eingabewerte für
amount, clientId, products, services, officeIdund Senden geeigneter Fehler, wenn einer von ihnen fehlt oder ungültig ist. - Was tun, wenn ein Produkt angegeben wird, das nicht in Ihrer Datenbank gefunden wird?
- Ein 404-Fehler ist möglicherweise nicht geeignet, wenn Sie einen Datenbankfehler erhalten (der wahrscheinlich ein 500-Fehler wäre).