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

Node.js Mongoose嵌套findOne调用:获取闪卡集合ID并写入JWT

问题解决:登录时正确获取Flashcard Collection ID并存入JWT

问题原因

getCollectionId是异步函数,调用时未等待其执行完成就直接赋值,导致loadedFlashcardCollection是Promise对象而非实际的集合ID,调用toString()后就会显示[object Promise]。

修复方案

将整个登录逻辑改为async/await风格,确保所有异步操作完成后再执行后续代码,同时修复getCollectionId中的错误处理:

//Request email, password -> find user with email -> if no user throw error -> get password -> decrypt and compare -> if false throw error -> if true generate JWT token
//JWT secret == JWTSECRETKEY , Expires in 2 hours
exports.login = async (req, res, next) => {
    const email = req.body.email;
    const password = req.body.password;
    try {
        // 1. 查询用户
        const loadedUser = await User.findOne({ email: email });
        if (!loadedUser) {
            const error = new Error('A user with this email does not exist');
            error.statusCode = 401;
            throw error;
        }

        // 2. 验证密码
        const isEqual = await bcrypt.compare(password, loadedUser.password);
        if (!isEqual) {
            const error = new Error("Wrong Password");
            error.statusCode = 401;
            throw error;
        }

        // 3. 等待获取集合ID(关键:用await等待异步函数完成)
        const loadedFlashcardCollection = await getCollectionId(loadedUser._id);

        // 4. 生成JWT令牌
        const token = jwt.sign(
            { 
                email: loadedUser.email, 
                userId: loadedUser._id.toString(), 
                collectionId: loadedFlashcardCollection.toString() 
            }, 
            'JWTSECRETTOKEN', 
            { expiresIn: '2h' }
        );

        // 5. 返回响应
        res.status(200).json({ 
            token: token, 
            userId: loadedUser._id.toString(), 
            collectionID: loadedFlashcardCollection.toString() 
        });
    } catch (err) {
        if (!err.statusCode) {
            err.statusCode = 500;
        }
        next(err);
    }
}

// 修复错误处理:未定义的error变量
async function getCollectionId(loadedUserID) {
    const collection = await flashcardCollection.findOne({ userID: loadedUserID });
    if (!collection) {
        const error = new Error(`No collection found.`);
        error.statusCode = 401;
        throw error;
    }
    return collection._id;
}

核心修改点

  • 将login函数标记为async,用try/catch统一处理异步错误
  • 所有异步操作(findOne、bcrypt.compare、getCollectionId)前添加await,确保拿到实际返回值而非Promise
  • 修复getCollectionId中未定义的error变量问题
  • JWT payload中字段名改为更清晰的collectionId(可选,原loadedFlashcardCollection也可)

关键注意事项

异步函数(标记async的函数)调用时,必须通过await或者.then()处理才能拿到最终结果,直接赋值只会得到Promise对象,无法直接使用其返回值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 19:57:38