• node-orm2


    最近应老大要求,对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~

  • 相关阅读:
    过滤器
    联系数据库 电话本例子
    连接数据库日志例题
    登录注册 servlet
    Pandas截取列部分字符,并据此修改另一列的数据
    Excel 如何判断某列哪些单元格包含某些字符
    Pandas逐行读取Dateframe并转为list
    Pandas: 使用str.replace() 进行文本清洗
    如何在xlwt中编写多个列的单元格?
    python:循环定义、赋值多个变量
  • 原文地址:https://www.cnblogs.com/showtime813/p/4552086.html
Copyright © 2020-2023  润新知