文档地址:bookselfjs.org、knexjs.org
之前项目用的mysq数据框架bookshelf(基于knex),基本操作文档以及demo。
var baseBookshelf = require('./base/index'), User, Users; //继承父类 User = baseBookshelf.Model.extend({ tableName: 'users' //表名定义 },{//行为封装、基于增删改查,输入数据校验,输出格式化等等吧! add: function add(data, options) { return baseBookshelf.Model.add.call(self, data, options); } }); Users = baseBookshelf.Collection.extend({ model: User });module.exports = { User: baseBookshelf.model('User', User), Users: baseBookshelf.collection('Users', Users) };
var dataProvider = require('../../common/models');
dataProvider.User.add({ name: name , phone: account , password: pass }).then(function (result) { res.sendStatus(200); }).catch(function(error) { //异常处理 });
//根据 phone字段 dataProvider.User.findOne({phone:phone}).then(function (user) { });
//根据 phone字段 dataProvider.User.destroy({phone:phone}).then(function (user) { });//TODO:没测试。。后续写个增删改查的用户管理,再完善
1、在fetch的时候尽量加上option参数{required:true} 这样如果没有结果会自动返回Promise.reject(NotFoundError) 并且尽量只select 需要查询/修改的字段 {columns:[...]} save的时候加上option参数{required:true} ,如果save失败会自动返回Promise.reject(NoRowsUpdatedError) 2、添加:save({method:'insert'}) 3、复杂条件查询使用query:
Model.query(functoin(qb){ if(content){ var likeContent = '%'+content+'%'; qb.where('name','like',likeContent) }; if(type_id){ qb.where('type_id','=',type_id) }; if(column){ qb.orderBy(column, order||'asc'); } qb.limit(10).offset(5) }).fetch()....
where: (condition1 && condition2) || condition3
qb.where(function(qb2){ qb2.where(condition1).andWhere(condition2) }).orWhere(condition3)
例:联表查询 consult.id、consult.content、commodity.name、user.*
var Consult = bookshelf.Model.extend({ tableName: 'mall_consult', commodity:function(){ return this.belongsTo(Commodity, "commodity_id"); // commodity_id: 该model中的外键 }, user:function(){ return this.belongsTo(User, 'user_id'); } } })var Commodity = bookshelf.Model.extend({ tableName: 'mall_commodity' consults:function(){ return this.hasMany(Consult, 'commodity_id'); //commodity_id: 目标model中的外键 } })
//联表查询 consult.id consult.content commodity.name user.*
{joinQuery : function (){ return this.where(条件).fetch({ columns:['id','content','commodity_id','user_id']}, //这里必须包括外键 required:true, withRelated:[ { commodity:function(qb){qb.column(['id','name']) // 这里column或者select里必须包含与原model外键对应的column; //query builder可以执行一系列查询操作 详见http://knexjs.org/ },'user'] ).then(function(resp){ return resp; }) }}
user (this表),follow_disease (Interim表),disease (target表)
通过follow_disease 查询user所关注的疾病名称
var user = bookshelf.Model.extend({ tableName:"user", disease_followed:function(){ return this.hasMany(disease).through(follow_disease,'id').query(function(qb){ qb.column(['disease.id','disease.name']) }) } })
var follow_disease= bookshelf.Model.extend({ idAttribute:'disease_id', tableName:"follow_disease", })
var disease = bookshelf.Model.extend({ tableName:"disease_followe" })
user.where({uid:uid}).fetch({withRelated:['disease']})
在我们现在的版本中,through中第二个参数是target表的主键,管理表需要设置idAttribute=管理表中关联到target表的外键(hasMany关系是这样,其他关系有待验证)
through 的具体用法在文档中没有写明,但作者已经在github上更新了through的用法,最新版本的bookshelf trough应该是这样
this.hasMany(Target).through(Interim, throughForeignKey, otherKey)
例子: 添加一个评论时,相应的商品表数据更新 注意:在所有save操作中请传option参数{transacting:事务参数 例子中的a_transacting} 如果没法在一个handler里面处理所有操作,请手动commit和rollback事务 comment:
addComment: function(){ var comment = {id:7,content:'pretty good!',level:2,commodity_id:27} var self = this; return baseBookshelf.transaction(function(a_transacting){ console.log('begin') return self.add(comment,{required:true,transacting:a_transacting,method:'insert'}) .then(function (result){ return dataProvider.Commodity .updateScore(comment.commodity_id,{transacting:a_transacting}) .then(a_transacting.commit) .catch(a_transacting.rollback) }) }) .then(function(resp){ return resp;}) .catch(function(err){ return Promise.reject(new baseBookshelf.Model.NoRowsUpdated());}) }
commodity
updateScore:function(id,option){ return this.where({id: id}).fetch(option).then(function (result) { /*处理result*/ return result.save(param,option); }) }
添加 评价时:更新该商品评分、修改该订单变为不可评论
var self = this; return baseBookshelf.transaction(function(t){ return Promise.try(function(){ return [ self.add(comment,{required:true,transacting:t}), dataProvider.Commodity.updateScore(comment.commodity_id, comment.level,t), dataProvider.Order.comment(comment.order_id,t) ] }) .all().then(t.commit).catch(t.rollback) }) .then(function(resp){return resp}) }