编写可复用的代码一直都是一名编程爱好者乐此不疲的事情,尤其像操作mongodb每次都需要连接数据库确实很麻烦,且会让代码显得臃肿杂乱
首先,新建一个文件,我命名为curd,这里封装着一个类,我会将所有的curd操作通过类来实例化调用,比如DB.find,我还需要一些辅助的方法或属性,比如_ope,this.tips
class DB{
constructor(){
this.tips = ""
this.query = []
this.charts = []
this.methods = []
}
static hasInstance(){}
_canNext(){}
_ope(){}
_connect(){}
_find(){}
_update(){}
_delete(){}
_add(){}
trigger(){}
}
如果您读过这篇nodeJs操作mongodb的文章(https://www.jianshu.com/p/e79ae43186b2),那么您应该会像我这样做
在DB类上新增方法trigger,该方法作为DB类向外暴露的唯一接口用来切换调用内部的CURD,因此我将每一个CURD方法前增加"_"表示这是一个私有方法
我希望当用户调用trigger方法时,我可以根据用户传递的CURD指定切换调用内部的_CURD指令,我还至少需要用户告诉我我要链接的数据库地址以及我要操作的表的名称,故我考虑这样实现trigger
trigger(operate,params){
this.query = params.jsons?params.jsons:[]
let str = ''
switch(operate){
case 'find':
str = '查询' break
case 'update':
str = '更新' break
case 'add':
str = '添加' break
case 'delete':
str = '删除' break
}
this.tips = str
if(operate=='find'){
this._find(params)
}else{
this._ope(params)
}
}
其中:
1.this._find()方法被单独拎出来,因为find方法获取操作结果的方式比较特殊,且find方法的"固定性较弱"
2.switch方法根据传递的操作名称动态修改是this.tips的值,this.tips将作为操作结果的msg返回
3.this.query用户传递的参数,考虑到某些操作会不止一个,故以数组进行保存
4-operate是用户要执行的操作,params是用户携带的查询方法,至少包括如下{collection:String,jsons:Array}
实现_ope方法
_ope(operate,params){
return new Promise((resolve,reject)=>{
this._connect().then(db=>{
db.collection(params.collection)[operate](...this.query,(err,data)=>{
if(err){
reject({
status:0,
msg:`${this.tips}失败~`
})
}
resolve({
status:1,
msg:`${this.tips}成功~`
})
})
})
})
}
其中:
1.this._connect方法用户连接数据库,数据库连接成功后返回db对象
2.db.collection(params.collection)[operate]用来连接表,相当于db.chartName.operate (可参考:)
3....this.query对参数对象进行展开,当执行如更新时有用
实现_find
_find(params){
this._connect().then(db=>{
db.collection(params.collection)[operate](...this.query).toArray((err,data)=>{
if(err){
reject({
status:0,
msg:`${this.tips}失败~`
})
}
resolve({
status:1,
msg:`${this.tips}成功~`
})
})
})
}
其中:
1..toArray就是一开始分析时候把find单独拿出来的原因之一
实现_connect
_connect(params){
return new Promise((resolve) => {
params.MongodbClient.connect(params.dbUri, {
useUnifiedTopology: true
}, (err, client) => {
if (err) {
throw new Error(err)
}
let db = client.db(params.dbName)
resolve(db)
})
})
}
其中:
1.MongodbClient是引入的数据库模块下客户端属性
2.dbUri是连接的数据库地址
3.dbName是要连接的数据库
至此,理论上看着已经大功告成了,其实,还差一点
差点什么呢?
1.如果多次实例化就会多次连接,每次连接都是耗时的
2.如果用户提供了DB类不支持的方法或者连接的数据库或表不存在应该提示用户
故
定义this.charts用来保存可操作的表;定义this.methods保存可执行的方法;定义_canNext并在trigger内调用来解决问题2
_canNext(params,operate){
if (!this.charts.includes(params.collection)) {
throw new Error("数据库" + params.dbName + '不存在' + params.collection + '表')
}
if (!this.methods.includes(operate)) {
throw new Error("DB类不存在方法" + method)
}
}
定义hasInstance以单例形式解决问题1,并在this._connect中调用,在导出时导出该方法而不是类DB
static hasInstance(){
if (!Db.instance) {
Db.instance = new Db()
}
return Db.instance
}
至此,大功告成!!!
网友评论