You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mongoose异步查询结果无法推入数组 返回no items问题

问题描述

使用Mongoose执行查询时可以正常匹配到目标数据,但无法将查询结果推入目标数组,代码运行输出no items,本质是异步函数执行时序问题:日志打印触发时,数据推入操作还未执行完成。

原问题代码如下:

const getOrders = function(allOrders){
    let promise = new Promise((succ, fail)=>{
        let ordersTodisplay = []
        for (let order of allOrders) {
            if (!(order.orderId === null || order.orderItem === null)){
                postMong.findById(order.orderItem, function (err, item) {
                    ordersTodisplay.push(item) 
                })
            }  
        } 
        if(ordersTodisplay.length > 0){
            succ(ordersTodisplay)    
        } else{
            fail("no items")
        }
    })
    return promise
}
router.get('/accountpage',function(req,res){ 
    const userDB = req.session.username
    if (userDB !== undefined && userDB){
        userForm.findOne({ username : userDB }, function (err, user) {
            const userOrders = user.userOrders;
            if (userOrders.length > 1) {
                getOrders(userOrders).then((result)=>{console.log(result)}, (fail)=>{console.log(fail)})
                res.render('../view/accountpage',{username: userDB,orders: itemsToDisplay});
            }
            else{
                res.render('../view/accountpage',{username: userDB,orders: "There are no orders"});
            }
        });
    } else {
        res.redirect("/login")
    }
});
问题原因
  • postMong.findById是异步回调函数,for循环是同步执行的,循环遍历完成时所有数据库查询的回调还没触发,此时ordersTodisplay是空数组,直接走失败分支返回no items。
  • 路由逻辑存在额外问题:getOrders是异步返回Promise的函数,代码没有等待Promise返回结果就提前执行res.render,且引用了未定义的变量itemsToDisplay,就算查询完成也会触发变量未定义错误。
修复代码
const getOrders = async function(allOrders){
    // 提前过滤无效订单
    const validOrders = allOrders.filter(order => order.orderId !== null && order.orderItem !== null)
    // 等待所有数据库查询执行完成
    const ordersTodisplay = await Promise.all(
        validOrders.map(order => postMong.findById(order.orderItem).exec())
    )
    if(ordersTodisplay.length > 0){
        return ordersTodisplay
    }
    throw new Error("no items")
}

router.get('/accountpage', function(req,res){ 
    const userDB = req.session.username
    if (!userDB) {
        return res.redirect("/login")
    }
    userForm.findOne({ username : userDB }, async function (err, user) {
        if(err) return res.status(500).send("服务异常")
        const userOrders = user.userOrders;
        if (userOrders.length > 0) {
            try {
                const orderList = await getOrders(userOrders)
                console.log(orderList)
                res.render('../view/accountpage',{username: userDB, orders: orderList});
            } catch (e) {
                console.log(e)
                res.render('../view/accountpage',{username: userDB, orders: "There are no orders"});
            }
        } else {
            res.render('../view/accountpage',{username: userDB, orders: "There are no orders"});
        }
    });
});
修复要点
  • 不要在同步循环中嵌套异步回调后立刻判断结果,用Promise.all等待所有异步查询全部执行完毕,再做结果校验和返回,彻底解决时序问题。
  • Mongoose查询调用.exec()方法可以返回标准Promise,配合async/await书写异步逻辑更清晰,不需要手动构造Promise包装。
  • 路由层必须等待异步查询拿到最终结果后,再执行res.render返回响应,禁止在异步操作未完成时提前返回响应,同时保证变量名一致,不要引用未定义的变量。
  • 原代码判断订单数量的条件userOrders.length > 1存在逻辑问题,用户仅有1条有效订单时会被判定为无订单,可根据实际业务需求调整判断阈值。

内容的提问来源于stack exchange,提问作者Cristian Babalau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 22:27:24