最近应老大要求,对orm2进行再一步封装,所以记录下封装和使用心得(文中数据库:mysql)。

数据库连接

var orm = require("orm");

orm.connect("mysql://username:password@host/database", function (err, db) {
}

实际情况: 由于公司产品比较多,每个产品就会有一个数据库,所以我们做底层的必须连接各个产品的数据库。

所以解决方案:

1.配置文件中将所有数据库都配置好,如下:

server: {
mysql: {
product: {
host: '',
user: '',
password: '',
database: '',
port: 3306,
multipleStatements: true,
insecureAuth: true
},
ss: {
host: '',
user: '',
password: '',
database: '',
port: 3306,
multipleStatements: true,
insecureAuth: true
}
}
}

2.定义全局DB操作对象

global.dbs = {};

3.通过bluebird,underscore等包,类似循环连接数据库,并保存链接,下面为部分代码

var   _ = require('underscore'),
promise = require('bluebird'); /**
* 初始化数据库连接
* @param conn 数据库连接字符串
* @param dbServer 数据库服务器
* @param callback
*/
var toDB = function (conn, dbServer, callback) {
orm.connect(conn, function (err, db) {
//连接错误,则抛出异常
if (err) return comm.nextTick(err, callback);
//将数据库连接存入全局数据库连接对象中
dbs[dbServer] = db;
comm.nextTick(null, dbs, callback);
})
} //toDB函数promise化
var toDBPrms = promise.promisify(toDB); //?pool=true为开启连接池
var connections = _.map(config.server.mysql, function (connection, key) {
return toDBPrms('mysql://' + connection.user + ':' + connection.password + '@' + connection.host + '/' + connection.database + '?pool=true', key);
}); promise
.all(connections)
.then(function () {
console.log('数据库连接成功');
})
.catch(function (err) {
log.error({'数据库连接错误:': JSON.stringify(err)});
})

Model定义

官方的Model加载定义是在连接数据库的时候,如下:

orm.connect("mysql://username:password@host/database", function (err, db) {
if (err) throw err; var Person = db.define("person", {
name : String,
surname : String,
age : Number, // FLOAT
male : Boolean,
continent : [ "Europe", "America", "Asia", "Africa", "Australia", "Antartica" ], // ENUM type
photo : Buffer, // BLOB/BINARY
data : Object // JSON encoded
} .......

可是这样太冗余,对于大项目表又多的情况明显不合适,所以它还有一种加载定义Model方式,即Model作为单独的一个文件。

//定义表结构Model
module.exports = function (db, cb) {
//define方法的第一个参数为表名
db.define('xxx', {
innerid: { type: 'serial', key: true } , //主键
name: String,
identifying: String,
purpose_code: Number,
org_id: String,
position_x: Number,
position_y: Number,
isenabled: Number,
isdeleted: Number
});
return cb();
}

加载

 //db为数据库连接,相当于connection;  load第一个参数为Model的路径
db.load('XXX', function (err) {
//加载model错误,记录异常
if (err) {
return callback(err,xxx);
}
callback(null,xxx);
})

数据插入

Model.Create:

Person.create([
{
name: "John",
surname: "Doe",
age: 25,
male: true
},
{
name: "Liza",
surname: "Kollan",
age: 19,
male: false
}
], function (err, items) {
// err - description of the error or null
// items - array of inserted items
});

下面是我对其进行封装

/**
* 数据添加
* @param dbServer db服务器
* @param modelName model名字
* @param entity 插入数据(JSON格式)
* @param callback 返回结果
*/
daoComm.prototype.create = function (dbServer, modelName, entity, callback) {
//数据库连接,dbs里面存了各个产品的数据库,所以要获取对应的数据库连接
var db = dbs[dbServer];
//连接不存在,则抛错
if (!db) return comm.nextTick(comm.response(config.status.FAILURE, 'DB Connection IS NOT Exist'), callback);
//model没加载,则自动加载
if (!db.models[modelName]) {
//加载model
loadModel(db, dbServer, modelName, function (err) {
//如有错误,则返回
if (err) return comm.nextTick(err, callback);
//执行插入数据操作
add(db.models[modelName], modelName, entity, callback);
});
} else {
//执行插入数据操作
add(db.models[modelName], modelName, entity, callback);
}
}
/**
* 实际插入数据操作
* @param model model对象
* @param modelName 表名
* @param entity 插入数据
* @param callback 返回值
*/
function add(model, modelName, entity, callback) {
model.create(entity, function (err, resItems) {
if (err) return comm.nextTick(comm.response(config.status.FAILURE, modelName + ' Data Insert ERROR : ' + err), callback);
return comm.nextTick(null, comm.response(config.status.OK, resItems), callback);
})
}

数据查找

1.Model.get(第一个参数为id的值):

Person.get(4, function(err, person) {
console.log( person.fullName() );
})

2.Model.find([ conditions ] [, options ] [, limit ] [, order ] [, cb ])

Person.find({ name: "John", surname: "Doe" }, 3, function (err, people) {
// finds people with name='John' AND surname='Doe' and returns the first 3
});

3.Model.find链式写法

Person.find({ surname: "Doe" }).limit(3).offset(2).only("name", "surname").run(function (err, people) {
// finds people with surname='Doe', skips first 2 and limits to 3 elements,
// returning only 'name' and 'surname' properties
});

这里数据查找的方法比较多。要再次封装的时候头很大,封装链式太麻烦;封装第二个find方法,参数又不固定,如何只取当中几列啥的文档也没写清楚,原来limit,offset,only这些都能放在options里面,所以最后还是看底层源码解决的...

/**
* 数据查询
* @param dbServer db服务器
* @param modelName model名字
* @param conditions 查询条件(json)
* @param options 查询选项(json) {"offset":2,"limit":3,"only":["innerid","name"]} offset跳过条数 limit查询条数 only:取的列
* @param order 排列(object) 例:["name","Z"],按name倒序
* 备注 传入的conditions,options,order都必须json.parse一下
* @param callback 返回结果
*/
daoComm.prototype.find = function (dbServer, modelName, conditions, options, order, callback) {
//数据库连接
var db = dbs[dbServer];
//连接不存在,则抛错
if (!db) return comm.nextTick(comm.response(config.status.FAILURE, 'DB Connection IS NOT Exist'), callback);
//参数没有时初始化
if (!conditions) conditions = {};
if (!options) options = {};
if (!order) order = [];
//判断参数类型
if (typeof conditions != "object" || typeof options != "object" || typeof order != "object") {
return comm.nextTick(comm.response(config.status.FAILURE, 'TypeOf Param Error'), callback);
}
//model没加载,则自动加载
if (!db.models[modelName]) {
//加载model
loadModel(db, dbServer, modelName, function (err) {
//如有错误,则返回
if (err) return comm.nextTick(err, callback);
//执行查询数据操作
query(db.models[modelName], modelName, conditions, options, order, callback);
});
} else {
//执行查询数据操作
query(db.models[modelName], modelName, conditions, options, order, callback);
}
}
/**
* 实际查询数据操作
* @param model model对象
* @param modelName 表名
* @param conditions 查询条件
* @param options 查询选项
* @param order 排序
* @param callback
*/
function query(model, modelName, conditions, options, order, callback) {
model.find(conditions, options, order, function (err, data) {
if (err) return comm.nextTick(comm.response(config.status.FAILURE, modelName + ' Data Query ERROR : ' + err), callback);
return comm.nextTick(null, comm.response(config.status.OK, data), callback);
})
}

可能这种封装方式也不好,希望各位大大能给点建议看看还有木有更好的~~

数据删除

简单来说就是先查后删Model.find().remove();

Person.find({ surname: "Doe" }).remove(function (err) {
// Does gone..
});

数据更新

稍微有点麻烦,先查后遍历修改再保存 Model.find().each().save()

Person.find({ surname: "Doe" }).each(function (person) {
person.surname = "Dean";
}).save(function (err) {
// done!
});

取COUNT

Model.find().count()

Person.find({ surname: "Doe" }).count(function (err, people) {
// people = number of people with surname="Doe"
});

判断是否存在

Model.Exists([ conditions, ] cb)

Person.exists({ surname: "Doe" }, function (err, exists) {
console.log("We %s Does in our db", exists ? "have" : "don't have");
});

函数使用

Model.aggregate

Person.aggregate({ surname: "Doe" }).min("age").max("age").get(function (err, min, max) {
console.log("The youngest Doe guy has %d years, while the oldest is %d", min, max);
}); //The same as "select avg(weight), age from person where country='someCountry' group by age;"
Person.aggregate(["age"], { country: "someCountry" }).avg("weight").groupBy("age").get(function (err, stats) {
// stats is an Array, each item should have 'age' and 'avg_weight'
});

官方给出这几个函数:min、max、avg、sum、count

groupBy只能在Model.aggregate中使用

多表查询

hasOne()、hasMany(),很遗憾,限制太多(具体哪些,自己去踩坑吧)俺不搞!

多表查询替代方法 && 直接执行SQL

db.driver.execQuery

db.driver.execQuery("SELECT id, email FROM user", function (err, data) { ... })

// 上面是直接执行SQL,下面是类似参数化。   列用??表示, 列值用?表示。   建议使用下面这种
db.driver.execQuery(
"SELECT user.??, user.?? FROM user WHERE user.?? LIKE ? AND user.?? > ?",
['id', 'name', 'name', 'john', 'id', 55],
function (err, data) { ... }
)

Sequelize也接触过一点点,不过感觉没ORM2上手那么容易,而且感觉ORM2的坑比较少 哈哈。

由于比较菜,各位在看本人自己封装的代码时吐槽时嘴下留情。 希望也能给本人多些建议,tks~

node-orm2的更多相关文章

  1. [转]为什么我要用 Node.js? 案例逐一介绍

    原文地址:http://blog.jobbole.com/53736/ 介绍 JavaScript 高涨的人气带来了很多变化,以至于如今使用其进行网络开发的形式也变得截然不同了.就如同在浏览器中一样, ...

  2. 【转】为什么我要用 Node.js? 案例逐一介绍

    原文转自:http://blog.jobbole.com/53736/ 介绍 JavaScript 高涨的人气带来了很多变化,以至于如今使用其进行网络开发的形式也变得截然不同了.就如同在浏览器中一样, ...

  3. Node.js(转) -- 临时来说还看不懂!

    转自:http://blog.jobbole.com/53736/ 本文由 伯乐在线 - Lellansin 翻译.未经许可,禁止转载!英文出处:toptal.欢迎加入翻译组. 介绍 JavaScri ...

  4. 为什么我要用 Node.js? 案例逐一介绍

    介绍 JavaScript 高涨的人气带来了很多变化,以至于如今使用其进行网络开发的形式也变得截然不同了.就如同在浏览器中一样,现在我们也可以在服务器上运行 JavaScript ,从前端跨越到后端, ...

  5. 为什么应使用 Node.js

    为什么应使用 Node.js JavaScript 高涨的人气带来了很多变化,以至于如今使用其进行网络开发的形式也变得截然不同了.就如同在浏览器中一样,现在我们也可以在服务器上运行 JavaScrip ...

  6. Node.js具体解析

    介绍 JavaScript 高涨的人气带来了非常多变化.以至于现在使用其进行网络开发的形式也变得截然不同了.就如同在浏览器中一样,现在我们也能够在server上执行 JavaScript ,从前端跨越 ...

  7. babeljs源码

    babel.min.js!function(e,t){"object"==typeof exports&&"object"==typeof mo ...

  8. node中通过orm2链接mysql的一个坑

    代码是orm上的例子,出现如下错误: ORMError: Connection protocol not supported - have you installed the database dri ...

  9. Node.js中的ORM

    ORM2是一款基于Node.js实现的ORM框架,名字相当的霸气,算是同类框架中非常出色的一款,具体介绍请猛击:https://github.com/dresende/node-orm2 刚接触Nod ...

  10. koa中间件系统原理及koa+orm2实践。

    koa是由 Express 原班人马打造的新的web框架.套用其官方的说法:Koa 应用是一个包含一系列中间件 generator 函数的对象. 这些中间件函数基于 request 请求以一个类似于栈 ...

随机推荐

  1. Linux(13):期中架构(5)--- 前端部分:keepalived高可用 & HTTPS & iptables防火墙

    keepalived 高可用集群 1. keepalived服务概念说明 # 1.1 keepalived软件的作用? Keepalived软件起初是专为LVS负载均衡软件设计的, 用来管理并监控LV ...

  2. N*N数码问题

    奇数码问题 时间限制: 1 Sec  内存限制: 128 MB 题目描述 你一定玩过八数码游戏,它实际上是在一个3*3的网格中进行的,1个空格和1~8这8个数字恰好不重不漏地分布在这3*3的网格中. ...

  3. 洛谷 [T21776] 子序列

    题目描述 你有一个长度为 \(n\) 的数列 \(\{a_n\}\) ,这个数列由 \(0,1\) 组成,进行 \(m\) 个的操作: \(1\ l\ r\) :把数列区间$ [l,r]$ 内的所有数 ...

  4. Codevs 1021 玛丽卡==洛谷 P1186

    时间限制: 2 s 空间限制: 128000 KB  题目等级 : 大师 Master  题目描述 Description 麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复. 因为她和他们不住在同一个 ...

  5. 【Codeforces Round #503 (Div. 2)】

    A:https://www.cnblogs.com/myx12345/p/9843198.html B:https://www.cnblogs.com/myx12345/p/9843245.html ...

  6. msp430入门学习40

    msp430的其他八 msp430入门学习

  7. MyBatis的参数,不能传入null

    今天在调试的过程中发现一个bug,把传入的参数写到查询分析器中执行没有问题,但是在程序中执行就报错:org.springframework.jdbc.UncategorizedSQLException ...

  8. 电音中DJ/Producer/MC/EDM/Remix/Mix的名词解释(转)

    DJ DJ是Disc Jockey的缩写,是电音圈子里的一种热门职业,一般大家在夜店或者酒吧看到的站在台上甩着膀子拧着按钮或者使劲儿搓碟的就是DJ啦. DJ的主要工作一般就是在现场用打碟机和混音台把许 ...

  9. SQL视图优化改写为存储过程遇到 双引号 单引号问题

    核心在于拼接SQL字符串中遇到中文双引号问题:   可以使用系统函数 替换掉set @pageStr =   replace(@queryStr,'"','''')  不过更推荐 使用两个单 ...

  10. Go -- 漫谈IM通信架构

    前前后后做的IM和推送系统已经有好几个了,一直都想好好总结下,因此就有了这篇文章.在我刚学编程的那会儿,觉得网络通信是一个很牛逼和门槛很高的一门技术,但是随着开源技术的发展和互联网知识的共享,现在要写 ...