mảng vấn đề async rỗng nodejs mongoose
tôi muốn lấy từ một loạt các ID có trong yêu cầu tên và giá của từng sản phẩm và lưu nó trong một mô hình mới (thanh toán), vì điều này, tôi xem qua từng sản phẩm và tìm id của nó trong db (Product.findById) và tôi lưu dưới dạng đối tượng trong arrayProducts những gì tôi cần (tên và giá), nhưng newPayment được tạo trước khi arrayProducts điền xong và tôi tạo nó trống, vì tôi có thể làm như vậy để tạo NewPayment sau khi forE từng sản phẩm kết thúc?
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 });
}
});;
});
Trả lời
Bạn cần thực hiện một số bài đọc về các hoạt động không chặn, không đồng bộ trong node.js. Của bạn Product.findById()là không chặn và không đồng bộ có nghĩa là lệnh gọi lại của nó được gọi là LONG sau khi toàn bộ trình xử lý tuyến đường của bạn đã hoàn thành việc thực thi và chắc chắn là sau khi console.log(arrayProducts);và tất cả mã xuất hiện sau đó.
Vì bạn muốn thực hiện N yêu cầu từ cơ sở dữ liệu của mình và bạn chỉ muốn biết khi nào chúng hoàn tất, cách hiệu quả nhất để làm điều đó là sử dụng giao diện Promise cho cơ sở dữ liệu của bạn, thu thập một loạt các lời hứa từ tất cả các hoạt động DB và sau đó sử dụng Promise.all()để thông báo khi tất cả đã hoàn thành.
Đây là những gì tôi muốn đề xuất:
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 });
}
});
Những thứ khác bị thiếu trong mã này là:
- Xác thực các giá trị đầu vào
amount, clientId, products, services, officeIdvà gửi các lỗi thích hợp nếu bất kỳ lỗi nào trong số đó bị thiếu hoặc không hợp lệ. - Phải làm gì nếu một sản phẩm được chỉ định không được tìm thấy trong cơ sở dữ liệu của bạn?
- Lỗi 404 có thể không phù hợp nếu bạn đang gặp lỗi cơ sở dữ liệu (có thể là lỗi 500).