var Site = bookshelf.Model.extend({
tableName: 'sites',
photo: function() {
return this.morphOne(Photo, 'imageable');
var Post = bookshelf.Model.extend({
tableName: 'posts',
photos: function() {
return this.morphMany(Photo, 'imageable');
var Photo = bookshelf.Model.extend({
tableName: 'photos',
imageable: function() {
return this.morphTo('imageable', Site, Post);
列名最好是用下划线的格式命名。
3 Bookshelf类
bookshelf对象的实例化,需要传入一个knex实例作为参数。
3.1 构造方法
new Bookshelf(knex)
3.2 成员
bookshelf.knex
返回被引用的knex实例
3.3 方法
bookshelf.transaction(transactionCallback)
返回事务处理回调函数的Promise实例
4 Model类
model通过指定表名以及与其他model的关系来表示单个数据库表(原文为individual database rows,不知道怎么翻译更好),可以通过特定的方法扩展。
4.1 构造方法
new Model (attributes, [options])
attributes,用于初始化model的属性
[options],指定表名,时间戳,解析器等
4.2 静态方法
Model.collection([models],[options])
实例化Collection对象,将当前model设置为collection的目标
返回Collection对象
Model.count([column],[options])
返回查找到的记录的数量。
Model.extend([prototypeProperties],[classProperties])
用于扩展bookshelf.Model类,扩展的方法都是直接定义在原型链上,子类可以继续扩展。
var checkit = require('checkit');
var Promise = require('bluebird');
var bcrypt = Promise.promisifyAll(require('bcrypt'));
var Customer = bookshelf.Model.extend({
initialize: function() {
this.on('saving', this.validateSave);
validateSave: function() {
return checkit(rules).run(this.attributes);
account: function() {
return this.belongsTo(Account);
login: Promise.method(function(email, password) {
if (!email || !password) throw new Error('Email and password are both required');
return new this({email: email.toLowerCase().trim()}).fetch({require: true}).tap(function(customer) {
return bcrypt.compareAsync(password, customer.get('password'))
.then(function(res) {
if (!res) throw new Error('Invalid password');
Customer.login(email, password)
.then(function(customer) {
res.json(customer.omit('password'));
}).catch(Customer.NotFoundError, function() {
res.json(400, {error: email + ' not found'});
}).catch(function(err) {
console.error(err);
Model.fetchAll()
获取给定model的全部实例
Model.forge([attributes], [options])
用于实例化Model的函数
4.3 成员
model.hasTimestamps
用于设置created_at
和updated_at
属性,如果要修改默认的列名,则传入一个数组,第一个元素用于替换created_at
,第二个元素用于替换updated_at
hasTimestamps: ['createdAt', 'updatedAt']
model.idAttribute
用于指定唯一键
model.tableName
用于指定model对应的数据库表名,不可缺省
4.4 方法
官方文档仅仅按字母顺序罗列了所有的方法,我按照各个方法的用途大致将其归类如下:
- 用于定义关系
- 用于操作数据库
- 用于操作属性
- 用于操作model
- 用于事件处理
4.4.1 用于定义关系的方法
model.hasOne(Target, [foreignKey])
用于定义一对一的关系。
Target,用于指明要关联的model
foreignKey,用于指明Target model的外键
返回Model
model.hasMany(Target, [foreignKey])
用于定义一对多的关系。
Target,用于指明要关联的model
foreignKey,用于指明Target model的外键
返回Collection
model.belongsTo(Target, [foreignKey])
用于和hasOne
以及hasMany
搭配使用。
Target用于指定与之产生关联的另一个model
foreignKey用于指定外键
返回model
model.belongsToMany(Target, [table], [foreignKey], [otherKey])
用于定义多对多的关系,即当前model通过(through)其他表与一个或多个Target关联(join)。
Target,用于指明与当前model关联的model
table,用于指明相互关联的那张表
foreignKey,用于指明当前model的外键
otherKey,用于指明Target model的外键
返回Collection对象
当相互关联的那张表有主键或是其他一些信息时,可以使用through
let Doctor = bookshelf.Model.extend({
patients: function() {
return this.belongsToMany(Patient).through(Appointment);
let Appointment = bookshelf.Model.extend({
patient: function() {
return this.belongsTo(Patient);
doctor: function() {
return this.belongsTo(Doctor);
let Patient = bookshelf.Model.extend({
doctors: function() {
return this.belongsToMany(Doctor).through(Appointment);
model.morphOne(Target, [name], [columnNames], [morphValue])
model.morphTo(name, [columnNames], …Target)
model.morphMany(Target, [name], [columnNames], [morphValue])
model.through(Interim, [throughForeignKey], [otherKey])
4.4.2 用于操作数据库的方法
model.count([column], [options])
column默认为*
对查询到的记录计数。
需要在query之后调用。
model.destroy([options])
用于执行delete
操作,用model的主键作为删除的约束条件。
会触发destroying
和destroyed
事件。
[options]
- [transacting] 按照事务的操作运行请求
- [require = true],会在没有删除任何内容的情况下抛出错误
Model.NoRowsDeletedError
// delete from `User` where id = 1
new User({id: 1})
.destroy()
.then(function(model) {
// ...
model.fetch([options])
用于执行select
操作,任何已经设置过的属性都可以作为约束条件。
会触发fetching
和fetched
事件。
[options]
- [require=false],当设置为true时,如果结果集为空,拒绝返回的响应并抛出错误
NotFoundError
- [columns=’*’],指定要取得的列(字段)
- [transacting],按照事务的操作运行请求
- [withRelated],要获得的关系
// select * from `books` where `ISBN-13` = '9780440180296'
new Book({'ISBN-13': '9780440180296'})
.fetch()
.then(function(model) {
// outputs 'Slaughterhouse Five'
console.log(model.get('title'));
复杂一些的例子:
let Book = bookshelf.Model.extend({
tableName: 'books',
editions: function() {
return this.hasMany(Edition);
chapters: function() {
return this.hasMany(Chapter);
genre: function() {
return this.belongsTo(Genre);
new Book({'ISBN-13': '9780440180296'}).fetch({
withRelated: [
'genre', 'editions',
{ chapters: function(query) { query.orderBy('chapter_number'); }}
}).then(function(book) {
console.log(book.related('genre').toJSON());
console.log(book.related('editions').toJSON());
console.log(book.toJSON());
model.fetchAll([options])
model.fetchPage(options)
按页获取数据库内容
pageSize为一页的记录数
page为总页数
model.load(relations, [options])
model.orderBy(sort, order)
对结果集排序
sort指定排序的标准(列名)
order指定升序(ASC)还是降序(DESC)
model.query(arguments)
用于构造请求。
model
.query('where', 'other_id', '=', '5')
.fetch()
.then(function(model) {
// ...
model
.query({where: {other_id: '5'}, orWhere: {key: 'value'}})
.fetch()
.then(function(model) {
// ...
model.query(function(qb) {
qb.where('other_person', 'LIKE', '%Demo').orWhere('other_id', '>', 10);
}).fetch()
.then(function(model) {
// ...
let qb = model.query();
qb.where({id: 1}).select().then(function(resp) {
// ...
model.resetQuery()
重置当前请求构造器的实例,会在每次数据库操作完成之后被Sync
自动调用。
model.where(method)
约束操作范围
4.4.3 用于事件处理的方法
model.on()
model.off()
model.once(nameOrNames, callback)
model.trigger()
model.triggerThen(name, […args])
4.4.4 用于操作属性(attribute)的方法
model.clear()
将model的所有属性清除。
返回model
model.escape(attribute)
用于去掉属性中的html元字符。
model.format(attributes)
用于在存入数据库之前,将属性格式化。
model.get(attribute)
用于获取给定的属性的值
model.has(attribute)
用于判断给定的属性是否已经有值
true表示有
false表示null或undefined
model.hasChanged([attribute])
用于判断属性值是否被更改过
true表示自上次fetch、save或destroy之后属性被修改过
false表示没有
如果没有指定参数,则任意属性被修改过都会返回false。
model.parse(response)
model.previous(attribute)
返回给定属性的上一个值,如果没有被修改过,则返回undefined。
model.previousAttributes()
返回上次修改之前的所有属性值。
model.refresh(options)
model.serialize([options])
将属性序列化(默认会序列化成JSON格式)
默认下,参数shallow=false,会将所有相关联的对象全部JSON化(调用toJSON)
model.set(attribute, [value], [options])
给属性设置值,
如果unset=true,表示移除该属性
model.toJSON([options])
会自动调用JSON.stringify方法。
model.unset(attribute)
用于移除给定的属性,如果不存在则不进行任何操作。
返回model。
4.4.5 用于操作model的方法
model.clone()
返回一个与model完全一样的新实例(所有属性,关系都相同)。
model.isNew()
用于检测model的id,来判断该model是否是新定义的。
model.related(name)
name表示要获取的关系
返回这个model定义的方法所指明的特定的关系,如果不存在则返回undefined。
model.save([key], [val], [attrs], [options])
用于对属性执行insert
或update
操作。
如果,在参数中设置{patch:true}
则只会进行更新操作。
这个过程会有几种事件类型
- “creating”
- “updating”
- “created”
- “updated”
- “saving”
- “saved”
insert的过程中触发creating、saving、created、saved
update的过程中触发updating、saving、updated、saved
model.timestamp([options])
给model添加时间戳属性
5 Event类
继承自Model和Collection
5.1 方法
event.off(name)
event.on(name,callback)
event.once(name,callback)
event.triggle(name,[...args])
event.triggleThen(name,[...args])
6 Knex Query Builder
bookshelf是基于Knex库构建的,许多语法需要参考knex。
其中最核心的部分就是请求构造器。
bookshelf.js 在过去的三年中,我们看到了JavaScript的普及率飙升。 多年来,已经进行了多次尝试将流行语言带入服务器 。 这些尝试中最流行的是Node.js ,它是作为编写服务器应用程序的快速方法提供给社区的。 无论从性能还是在开发时间上,Node的卖点都是速度。 随着这种受欢迎程度的提高,社区得到了发展,该项目受益于更多的贡献者,从而产生了诸如Express.js的高质量模块。...
在过去的三年里,我们已经看到在JavaScript中的人气激增。 多年来,有在服用通俗的语言给了多次尝试服务器 。 最这些尝试的盛行已经Node.js的 ,这是提供给社会编写服务器应用程序的快捷方式。 该卖点节点是速度,无论是在性能方面和开发时间。 有了这种流行的社区长大,项目从更多的贡献者获益,从而导致高品质的模块,如Express.js 。 其结果是人们开始建造使用节点完整的后端。 一个后...
bookshelf.js是基于knex的一个关系型数据库的ORM库。简单易用,内置了Promise的支持。这里主要罗列一些使用的例子,例子就是最好的教程。下面就是用mysql作为实例数据库表明bookshelf如何使用。其他的几个关系型数据库使用上基本一致,只是配置等地方需要使用的名称各自不同。为了更加贴近实际全部的例子都会放在Express打造的RESTful服务里。安装bookshelf和kne
术语事务指的是构成单一逻辑工作单元的操作的集合。比如:将钱从一个账户转到另一个账户就是一个事务,该事务包括分别针对每个账户的两个更新。
英文中transaction又是交易的意思,我想应该是因为事务(transaction)管理的场景首先是出现在利用银行账户进行交易(transaction)的过程中,所以计算机科学家们把数据库的这一特性称为事务(transaction)。
事务有以下几
LEFT JOIN的工作情况是这样的:你给出用来匹配两个数据表里的数据行的数据列,当来自左数据表的某个数据行与来自右数据表的某个数据行匹配时,那两个数据行的内容就会被选取为一个输出数据行;如果来自左数据表的某个数据行在右数据表里找不到匹配,它也会被选取为一个输出数据行,此时与它联结的是一个来自右数据表的“假”数据行,这个“假”数据行的所有数据列都包含NULL值。换句话说,在LEFT JOIN操作里,
////////////////////////////bookshelf and knex bookmark ////////////////
// target table sql
CREATE TABLE public.company
id integer NOT NULL,
name text COLLATE pg_catalog."default" NOT N...
bookshelf 详细介绍
一个基于Knex.js的Node.js ORM框架,支持PostgreSQL,MySQL和SQLite3
简单来说,Bookself是一个优秀的代码库,它易于阅读、理解、可扩展。它不强制你使用任何特定的校验scheme,而是提供灵活有效的关系或嵌套关系加载策略,一级类支持事务。它是一个精益的对象关系映射器(lean Obje...