ITPub博客

首页 > 数据库 > > Async/Await用于mongodb driver

Async/Await用于mongodb driver

作者:浪花小雨滴 时间:2020-05-12 11:41:03 0 删除 编辑

有个需求是这样的,解析好段子后,需要将段子永久化到本地数据库。本项目选用的MongoDB,原因是个人偏好。Javascript和MongoDB经常搭配起来用,这里并讨论该业务场景下的数据库选取。

在我的知识储备里,有两个npm包可以用来和MongoDB交互,一个是mongodb,另一个是mongoose,这里做一个区别。

mongodb的描述是

The official MongoDB driver for Node.js. Provides a high-level API on top of mongodb-core that is meant for end users.

mongoose的描述是

Mongoose is a MongoDB object modeling tool designed to work in an asynchronous environment.

可以看出来mongoose是更高一层的封装,是

elegant mongodb object modeling for node.js

但我们的需求很简单,就是存储,因此在这里选用了mongodb这个包。


写Nodejs有个很大的问题就是会写出回调地狱(callback hell)。回调地狱有个有趣的图片。

图片出处

对于这个问题的解决,大致经过了三个阶段,在此简要回顾。

  1. promise
  2. generator
  3. async/await

提供一些参考链接,有很详细的描述。

回调地狱的今生前世@JavaScript · Issue #17 · rccoder/blog

另外还有一些进一步的思考,提出了一种和async/await相类似但在目前阶段兼容又方便的方法,在此给出链接。基于 generator 与 promise 的异步编程解决方案


本文将采用async/await的方法。首先需要搭建es6的开发环境,请参考本专栏的第一篇文章,es6开发环境的搭建。

然后建立本地MongoDB环境,mac系统下的安装可以参考以下两个链接

Install MongoDB Community Edition on OS X

mac下安装mongodb

安装好后,使用以下命令后台运行MongoDB

mongod --dbpath xxx --logpath xxx --fork --port 27017

其中

--fork使程序运行在后台

--port指定MongoDB的端口

Mac下可以使用MongoHub这个软件看下连接的数据库,jeromelebel/MongoHub-Mac。


程序部分

首先需要安装mongodb包

npm install --save mongodb

创建两个文件mongoConnect.js和index.js

  • mongodbConnect.js:提供connect方法
  • index.js:主要程序逻辑

mongoConnect.js

import mongodb from 'mongodb'
const connect = mongodb.MongoClient.connect;
export default connect;

index.js

import connect from './mongoConnect';

connect("mongodb://localhost:27017/test")
.then(
    async (db)=>{
        const collection = db.collection('test');
        const res = await collection.insertOne({name: "test", age: 19});
        const result = await collection.find({}).toArray();
        console.log(result);        
        db.close();
    },
    (err)=>{
        console.log("db connection error")
        throw err;
    }
)

.catch((err)=>{
    console.log(err);
    dbConnect.close();
})

运行与输出

MongoHub查询结果


程序解释

connect("mongodb://localhost:27017/test")

connect因为没有加回调函数,因此将返回一个promise对象,用.then去承接。

为什么返回的是promise对象,可以参考官方文档,以及源码。

Class: MongoClient

贴一段源码, connect函数源码链接


接下来看then的部分。

.then(
    async (db)=>{
        const collection = db.collection('test');
        const res = await collection.insertOne({name: "test", age: 19});
        const result = await collection.find({}).toArray();
        console.log(result);        
        db.close();
    },
    (err)=>{
        console.log("db connection error")
        throw err;
    }
)

这里面用了async/await。collection.insertOne()和collection.find({}).toArray(),在没有回调函数传入的情况下会返回promise,因此await会阻塞程序,达到流程控制的目的。这样写代码精简且易读。

使用async/await还有一个重要的原因是方便管理db的关闭。如果只用promise来做,即用类似于以下的代码做。

.then(
   (db)=>{
        const collection = db.collection('test');
        return collection.insertOne({name: "test", age: 19});
    },
    (err)=>{
        console.log("db connection error")
        throw err;
    }
)
.then(
    (res)=>{
        ...
    },
    (err)=>{
        throw err;
    }
)

会碰到db无法关闭的问题。因为collection.insertOne({name: "test", age: 19})返回的promise对象给下面时,只传递了一个response过去,db并没有传递过去,这会导致连接一直存在着。这是用promise的一个固有问题,即只能传递一个变量到下一层;要传递多个变量,一般需要自己把它们封装成一个object,再传递下去。虽然可以通过设一个全局变量的解决,但很显然不够优雅。


参考链接

mac下安装mongodb

add db.close method? · Issue #261 · vitaly-t/pg-promise


程序地址

wk633/duanziMonitorSystem

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31537575/viewspace-3152144/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2018-05-16

  • 博文量
    4259
  • 访问量
    39969