zoukankan      html  css  js  c++  java
  • 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~

  • 相关阅读:
    题解 CF171G 【Mysterious numbers
    题解 P1157 【组合的输出】
    题解 P3955 【图书管理员】
    题解 P2036 【Perket】
    题解 CF837A 【Text Volume】
    题解 CF791A 【Bear and Big Brother】
    题解 CF747A 【Display Size】
    题解 P1332 【血色先锋队】
    题解 P2660 【zzc 种田】
    题解 P4470 【[BJWC2018]售票】
  • 原文地址:https://www.cnblogs.com/showtime813/p/4552086.html
Copyright © 2011-2022 走看看