首页 > 数据库 > > Async/Await用于mongodb driver
有个需求是这样的,解析好段子后,需要将段子永久化到本地数据库。本项目选用的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)。回调地狱有个有趣的图片。

对于这个问题的解决,大致经过了三个阶段,在此简要回顾。
提供一些参考链接,有很详细的描述。
回调地狱的今生前世@JavaScript · Issue #17 · rccoder/blog
另外还有一些进一步的思考,提出了一种和async/await相类似但在目前阶段兼容又方便的方法,在此给出链接。基于 generator 与 promise 的异步编程解决方案
本文将采用async/await的方法。首先需要搭建es6的开发环境,请参考本专栏的第一篇文章,es6开发环境的搭建。
然后建立本地MongoDB环境,mac系统下的安装可以参考以下两个链接
Install MongoDB Community Edition on OS X
安装好后,使用以下命令后台运行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
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对象,可以参考官方文档,以及源码。

贴一段源码, 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,再传递下去。虽然可以通过设一个全局变量的解决,但很显然不够优雅。
参考链接
add db.close method? · Issue #261 · vitaly-t/pg-promise
程序地址
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31537575/viewspace-3152144/ ,如需转载,请注明出处,否则将追究法律责任。