如何确保多异步MongoDB查询完成后再渲染页面?
如何确保MongoDB多集合异步查询完成后再渲染页面?
问题背景
需要从MongoDB多个集合中提取数组数据,现有单集合查询代码能保证异步任务完成,但无法同时获取多集合数据;错误写法直接将查询结果用于渲染,无法保证数据就绪,需解决多集合异步查询完成后再执行页面渲染的问题。
初始单集合查询代码
// connect to database. mongoose.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true }) .then((result) => app.listen(5000)) .catch((err) => console.log(err)) // create database object. const db = mongoose.connection; // render the page. app.get('/', (req, res) => { db.collection('links').find({...}) .then((result) => { res.render('index', { title: "Home", result, sites }) }) .catch((err) => { console.log(err) }) });
错误示例代码
// connect to database. mongoose.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true }) .then((result) => app.listen(5000)) .catch((err) => console.log(err)) // create database object. const db = mongoose.connection; const links_res = db.collection('links').find({...}) const sites_res = db.collection('sites').find({...}) // render the page. app.get('/', (req, res) => { res.render('index', { title: "Home", links_res, sites_res }) });
解决方案
核心思路是等待所有异步查询Promise完成后,再执行渲染操作,以下两种常用实现方式:
1. 使用Promise.all()处理并发查询
Promise.all()可以同时等待多个Promise完成,所有Promise成功resolve后,会返回包含所有结果的数组,此时再调用页面渲染:
mongoose.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true }) .then((result) => app.listen(5000)) .catch((err) => console.log(err)) const db = mongoose.connection; app.get('/', (req, res) => { // 定义多个查询Promise,调用toArray()获取实际数据(find()返回游标) const linksQuery = db.collection('links').find({...}).toArray(); const sitesQuery = db.collection('sites').find({...}).toArray(); // 等待所有查询完成 Promise.all([linksQuery, sitesQuery]) .then(([linksResult, sitesResult]) => { // 所有数据就绪,执行渲染 res.render('index', { title: "Home", links: linksResult, sites: sitesResult }) }) .catch((err) => { console.log(err); res.status(500).send('查询出错'); }) });
2. 使用async/await语法(更直观)
将路由处理函数标记为async,用await等待所有查询完成,代码可读性更强:
mongoose.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true }) .then((result) => app.listen(5000)) .catch((err) => console.log(err)) const db = mongoose.connection; app.get('/', async (req, res) => { try { // 并行执行两个查询,等待全部完成 const [linksResult, sitesResult] = await Promise.all([ db.collection('links').find({...}).toArray(), db.collection('sites').find({...}).toArray() ]); // 数据就绪后渲染页面 res.render('index', { title: "Home", links: linksResult, sites: sitesResult }); } catch (err) { console.log(err); res.status(500).send('查询出错'); } });
关键说明
- 错误写法的问题:
db.collection.find()返回的是游标对象,并非实际查询结果,且查询是异步的,直接赋值给变量时数据还未加载完成,渲染页面自然拿不到有效数据。 - 必须调用
toArray():将游标转换为包含查询结果的数组,才能在页面中使用具体数据。
内容的提问来源于stack exchange,提问作者user17949931
相关产品推荐
相关产品推荐

