在异步/等待Express路由器中使用MongoDB客户端的正确方法

时间:2018-09-12 10:19:21

标签: node.js mongodb express

在异步/等待Express路由器中管理MongoDB客户端的正确方法是什么?

我正在尝试在路由器中间件中创建MongoDB客户端,以便它可用于所有请求。这是一个简化的示例:

const express = require('express');
const { MongoClient } = require('mongodb');

let router = express.Router();

router.use(async (req, res, next) => {
    try {
        req.client = await MongoClient.connect(process.env.MONGODB_URI);
        next();
    } catch (err) {
        next(err);
    } finally {
        req.client && req.client.close();
    }
});

router.get('/', async (req, res, next) => {
    let user = await users.findOne({ name: 'foo' });
    if (!user) {
        user = { name: 'foo' };
        await users.insert(user);
    }
    res.json(user);
});

module.exports = router;

不幸的是,在调用await users.findOne({ name: 'foo' })之后,执行跳转到中间件中的finally分支,MongoDB连接已关闭,因此对await users.insert(user)的潜在调用因此失败。 / p>

感谢帮助!

1 个答案:

答案 0 :(得分:0)

您从哪里获得用户集合?

在正确地收集了用户的集合之后,您可以保证所有的数据库调用。

您可以使用Promise.all一次解决所有问题

const [user1, user2] = await Promise.all([users.findOne({name: 'user1'}), users.findOne({name: 'user2'})]);

这将同时解决两个承诺。

代码更新后编辑1

您可以使用{upsert: true}

const user = await users.findOneAndUpdate({name: 'foo'}, {name: 'foo'}, {upsert: true})

并且由于next()是异步调用,因此您的代码肯定会移动到finally块。

const express = require('express');
const { MongoClient } = require('mongodb');

let router = express.Router();

router.use(async (req, res, next) => {
    try {
        req.client = await MongoClient.connect(process.env.MONGODB_URI);
        next();
    } catch (err) {
        next(err);
    }
});

router.get('/', async (req, res, next) => {
    let user = await users.findOne({ name: 'foo' });
    if (!user) {
        user = { name: 'foo' };
        await users.insert(user);
    }
    res.json(user);

    next();
});

router.use(async (req, res, next) => {
    try {
        req.client && req.client.close();
    } catch (err) {
        next(err);
    }
})

module.exports = router;