[英]Fetching data from mongo via express, build object, and send to React
我目前陷入异步地狱。 在我的 React 中,我有一个页面 /menu,它将通过 expressjs api 从我的 mongo 实例加载数据。
在我的名为 menu 的数据库中,我有 collections 代表膳食类型,例如“早餐”、“午餐”等。在这些 collections 中,每个项目的文档看起来像这个面包集合示例:
{
_id: 2398jcs9dn2f9f,
name: "Ciabatta",
desc: "Italian bread",
imageURI: "image01.jpg",
reviews: []
}
这是我的 api 将在页面加载时调用
exports.getAllFoods = (req, res, next) => {
const db = mongoose.connection
const allCollections = {}
try {
db.db.listCollections().toArray((err, collections) => {
collections.forEach((k) => {
allCollections[k.name] = []
})
Object.keys(allCollections).map(k => {
let Meal = mongoose.model(k, MealSchema)
meal = Meal.find((err, docs) => {
allCollections[k] = docs
console.log(allCollections)
})
})
res.send(allCollections)
})
} catch (error) {
console.log(error)
res.send('unable to get all collections')
}
}
console.log(allCollections) 的最后一个 output 产生这个:
{ snacks:
[ { review: [],
tags: [],
_id: 5fcec3fc4bc5d81917c9c1fe,
name: 'Simosa',
description: 'Indian food',
imageURI: 'image02.jpg',
__v: 0 } ],
breads:
[ { review: [],
tags: [],
_id: 5fcec41a4bc5d81917c9c1ff,
name: 'Ciabatta',
description: 'Italian bread',
imageURI: 'image02.jpg',
__v: 0 } ],
}
这正是我所需要的,但我一直在弄清楚如何发送到 React。 发送上述 json 怎么办? res.send(allCollections) 给了我这个:
{
"snacks": [],
"breads": [],
"drinks": []
}
我理解为什么要发送上述内容,但我不知道我需要做些什么来解决它。
这是我在页面加载时的反应
useEffect(() => {
axios
.get('http://localhost:8888/api/allFoods')
.then((res) => {
setMealTypes(res.data)
})
.catch((err) => [
console.log(err)
])
}, [])
最终,我需要在控制台中输出 json,因为我想遍历该数据并将键用作标题,然后列出值数组中的值,例如
<div>
<h2>Breads</h2>
<img src=image01.jpg/>
<h3>Ciabatta</h3>
<p>Italian bread</p>
...
</div>
...
我很感激任何帮助,以及我应该阅读的任何文档以帮助和改进我对 javascript 的理解
我更喜欢使用async
/ await
和Promise.all
来解决这个问题,替换大多数回调。
因为你在遍历数组时调用了数据库,所以你遇到了最烦人的回调情况:你如何发出一堆异步的东西,然后得到结果? 您需要其他东西来确保在发送结果之前调用所有回调。
异步/等待意味着我们可以声明 function 是异步的,并等待异步操作的结果。 async/await 在 JS 中很烦人,因为它抽象出回调,实际上是在下面创建一个 Promise。 更复杂的是,async/await 并不能解决发出多个异步函数的问题,所以我们不得不再次依赖这个花哨Promise.all()
function 结合map
输入所需的数组到 async 函数。
原来的:
Object.keys(allCollections).map(k => {
let Meal = mongoose.model(k, MealSchema)
meal = Meal.find((err, docs) => {
allCollections[k] = docs
console.log(allCollections)
})
});
建议的异步/等待:
await Promise.all(Object.keys(allCollections).map(async k => {
let Meal = mongoose.model(k, MealSchema)
let docs = await Meal.find();
allCollections[k] = docs;
console.log(allCollections);
}));
另一个优点是错误处理。 如果原始示例的回调中发生任何错误,则不会在此 try/catch 块中捕获它们。 async/await 会像您期望的那样处理错误,并且错误最终会出现在 catch 块中。
...
// Now that we have awaited all async calls above, this should be executed _after_ the async calls instead of before them.
res.send(allCollections);
})
} catch (error) {
console.log(error)
res.send('unable to get all collections')
}
}
从技术上讲Promise.all()
返回一个结果数组,但我们可以忽略这一点,因为无论如何您都在格式化Object
。
有很多空间可以进一步优化。 我可能会把整个 function 写成这样:
exports.getAllFoods = async (req, res, next) => {
const db = mongoose.connection.db;
try {
let collections = await db.listCollections().toArray();
let allCollections = {};
collections.forEach((k) => {
allCollections[k.name] = [];
})
// For each collection key name, find docs from the database
// await completion of this block before proceeding to the next block
await Promise.all(Object.keys(allCollections).map(async k => {
let Meal = mongoose.model(k, MealSchema)
let docs = await Meal.find();
allCollections[k] = docs;
}));
// allCollections should be populated if no errors occurred
console.log(allCollections);
res.send(allCollections);
} catch (error) {
console.log(error)
res.send('unable to get all collections')
}
}
完全未经测试。
您可能会发现这些链接比我的解释更有帮助:
https://javascript.info/async-await
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
https://medium.com/dailyjs/the-pitfalls-of-async-await-in-array-loops-cf9cf713bfeb
I hope this will help you: You need to first use the stringify method before sending the collections from the express api and then use JSON.parse on the React front end to restore the object. PS:你能在 res.send(allCollections) 上面写一个 console.log(allCollections) 吗?
您需要以 JSON 格式将其发送到前端。
用res.json(allCollections)
替换res.send(allCollections)
allCollections)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.