使用typescript封装mongodb

疫情当前,大家足不出户,对于普通人来说,保护好身体,不生病,不给医护人员和国家添乱就是一种爱国的表现。

如果在这期间还能保持学习就是爱自己的表现。面对越来越严峻的互联网行业,自己也需要拓宽自己的视野,做好迎接挑战的准备。所以这段时间学了下koa和typescript,学完之后还是比较空洞,就像着看看能不能总结出自己的一套koa脚手架,首当其冲的一个任务就是用typescript封装mongodb。

为什么要封装mongodb

其实目前已经有很好的第三方框架了mongoose,这个已经非常好用了。为什么自己还要封装了。

当然是出于学习的目的

自己封装的可以更小,更灵活

准备工作

封装之前需要理解一下几个点

typescript的语法(class, 泛型, 接口)

异步编程(promise, async, await)

设计模式(单例模式)

node-mongodb-native第三库的使用。

mongodb数据库语法

因为我是在node-mongodb-native的基础进行二次封装,所以肯定要了解这个框架的使用。git网址:github.com/mongodb/nod… 查看readme就能明白库的基本用法。只是下面一点需要注意

const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
// Connection URL
const url = 'mongodb://localhost:27017';
// Database Name
const dbName = 'myproject';
// Use connect method to connect to the server
MongoClient.connect(url, function(err, client) {
assert.equal(null, err);
console.log("Connected successfully to server");
const db = client.db(dbName);
client.close();
});

复制代码这是官网连接数据库的例子,当你的数据库设置了用户权限这个就不适用。

const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
// Connection URL
const url = 'mongodb://jgmiu:jgmiu090840@127.0.0.1:27017/testdb'; // 这里跟上了数据库名以及该数据库的用户名以及密码
// Database Name
// const dbName = 'myproject'; 由于连接字符串跟上了数据库名,所以不需要这样
// Use connect method to connect to the server
MongoClient.connect(url, function(err, client) {
assert.equal(null, err);
console.log("Connected successfully to server");
const db = client.db();// 这里也不需要跟上数据库名
client.close();
});

复制代码我英文不好,所以在官方文档上没有查看到怎么连接由用户权限的方法,这个是我试出来的。

开始封装

准备工作做好之后下面开始一步一步开始封装。

创建config文件

新建config.ts的配置文件,配置如下

const config = {
url: 'mongodb://jgmiu:jgmiu090840@127.0.0.1:27017/testdb'
}
export default config

复制代码

引入第三方库

安装mongodb

npm install --save mongodb

复制代码

DBI接口创建

新建db.ts文件,并进行接口编写如下

interface DBI {
// 插入
insert(collectionName:string, doc:T):Promise
// 批量插入
insertMany(collectionName:string, docs:T[]):Promise
// 删除
delete(collectionName:string, filter:object):Promise
// 更新
update(collectionName:string, filter:object,update:object):Promise
// 查找
find(collectionName:string, filter:object):Promise
// 高级查找
aggregate(collectionName:string, pipeline:object[]):Promise
}

复制代码

创建单例模式的Db

为了保证数据库连接只有一个实例,所以我们自立必须使用单例模式

class Db {
static instance:Db | null
static getInstance() {
if(!Db.instance) this.instance = new Db()
return this.instance
}
constructor() {
console.log('constructor')
}
}
const db = Db.getinstance()
const db1 = Db.getinstance()

复制代码

以上就是一个最简单的单例模式,db与db1是同一个实例

连接数据库

下面我们要连接数据库

import config from './config'
import mongodb from 'mongodb'
const MongoClient = mongodb.MongoClient
class Db implements DBI {
public client:mongodb.MongoClient | undefined
static instance:Db | null
static getInstance() {
if(!Db.instance) this.instance = new Db()
return this.instance
}
constructor() {
console.log('constructor')
this.connection()
}
connection():Promise {
return new Promise((resolve, reject) => {
if(!this.client) {
MongoClient.connect(config.url, {useUnifiedTopology:true}, (err, client) => {
if(err){
reject(err)
} else {
console.log('db server start success!')
this.client = client
resolve(client)
}
})
} else {
resolve(this.client)
}
})
}
}

复制代码有一下几点说明

public client:mongodb.MongoClient | undefined 这里的client必须要申明为MongoClient类型,如果生命为any类型会编译不通过

连接数据库是一个比较耗时的操作,所以我们每次连接前我们判断this.client是否已经存在,存在我们就不会再去连接。

注意这里返回的是:Promise。后面很多方法我们都是返回的Promise

至此我们对多次实例与多次连接都做了相应的处理。

CRUD方法实现

我们准备工作做完了,接口定义好了,多次实例多次连接我们都做了相关处理,接下来就是实现增删改查了。这个过程虽然工作量比较大,但是也是最简单的。下面选一个增加的例子如下:

insert(collectionName:string, doc:T):Promise {
return new Promise((resolve, reject) => {
this.connection().then((client) => {
const db = client.db()
const result = db.collection(collectionName).insert(doc, (err, result) => {
if(err){
resolve(false)
reject(err)
} else {
resolve(true)
}
})
})
})
}

复制代码

在koa中使用

koa使用了async语法,而我们封装的方法基本都是返回的promise,所以写起来就非常方便

import Koa from 'koa'
import Router from 'koa-router'
import Db from './module/db'
const app = new Koa(),
router = new Router(),
db = new Db()
router.get('/', async (ctx) => {
const users = await db.find('users', {})
console.log(users)
// 测试添加
interface User{
name:string
}
const result = await db.insertMany('users',[{name: '888'}])
console.log(result)
ctx.body = 'index'
})
app.use(router.routes())
app.use(router.allowedMethods())
app.listen(3000, ()=>{
console.log('serve start on 3000')
})

复制代码