MONGOOSEDAO

    在核心J2EE模式中是这样介绍DAO模式的:为了建立一个健壮的J2EE应用,应该将所有对数据源的访问操作抽象封装在一个公共API中。用程序设计的语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口在逻辑上对应这个特定的数据存储。

    简单点理解是

    什么是mongoosedao

    mongoose是orm工具,提供了模型上的丰富的操作方法,但它的api可读性和操作易用性并不能满足我们dao的需求,我们需要有更简单的操作方法,于是mongoosedao应运而生。

    提供了很多使用api,他们都是模型上的方法,操作起来更加简便

    • create
    • delete = remove
    • deleteAll = removeAll
    • deleteById = removeById
    • getById
    • all = getAll = find({})
    • query = getByQuery = find
    • one = findOne
    • update
    • updateOne
    • updateById
    • pageByLastId
    • top(num) && first(num) = n(num) = latest(num)
    • count(cb) &* count({},cb)

      其实很简单,就是利用mongoose本身的一些特性,进行约定。

      1. if(!Model){
      2. throw new Error(Model + " is not valid, please check if it is a mongoose model!");
      3. }
      4. this.model = Model;
      5. this.pagesize = 20;
      6. }

    通过把Model作为参数,构建dao对象。

    别名,比如find我们把它绑定到dao上,可以叫find也可以叫query

    1. MongooseDao.prototype.query = MongooseDao.prototype.find = MongooseDao.prototype.getByQuery = function(query, cb) {
    2. this.model.find(query, cb);
    3. };

    比如count,有2种用法

    1. User.count(cb)

    按条件查询总数

    1. User.count({},cb)

    具体实现代码

    1. MongooseDao.prototype.count = function() {
    2. var query = {};
    3. var cb;
    4. //count({a:1},cb)
    5. if (arguments.length == 2) {
    6. query = arguments[0];
    7. cb = arguments[1];
    8. }else{
    9. //default : count(cb)
    10. cb = arguments[0];
    11. }
    12. this.model.count(query, cb);
    13. };

    更新依然

    1. // way1: conditions, update , cb
    2. // way2: conditions, update ,options, cb
    3. MongooseDao.prototype.update = function() {
    4. var conditions, update ,options, cb;
    5. var _options;
    6. if (arguments.length == 3) {
    7. _options = {}
    8. conditions = arguments[0];
    9. update = arguments[1];
    10. cb = arguments[2];
    11. }else if(arguments.length == 4) {
    12. conditions = arguments[0];
    13. update = arguments[1];
    14. _options = arguments[2];
    15. }else{
    16. throw new Error("MongooseDao.prototype.update param is not valid!")
    17. }
    18. var opt = { multi: true };
    19. _extend(opt, _options);
    20. this.model.update(conditions, update, opt, cb);
    21. };

    用法

    定义模型

    用法

    1. require('./db');
    2. var User = require('./User');
    3. User.create({"username":"sss","password":"password"},function(err, user){
    4. });
    5. User.delete({"username":"sss"},function(err, user){
    6. console.log(user);
    7. });

    获取指定前20条数

    1. Top.top(function(err, tops){
    2. if(err){
    3. console.dir(err);
    4. }
    5. // console.dir(tops.length);
    6. assert.equal(tops.length == 20, true);
    7. done();
    8. });

    获取指定前xx条数

    1. Top.top(30 ,function(err, tops){
    2. if(err){
    3. console.dir(err);
    4. }
    5. // console.dir(tops.length);
    6. assert.equal(tops.length == 30, true);
    7. done();
    8. });

    根据查询条件获取指定前xx条数

    1. Top.top(30, {}, function(err, tops){
    2. if(err){
    3. console.dir(err);
    4. }
    5. // console.dir(tops.length);
    6. assert.equal(tops.length == 30, true);
    7. done();
    8. });

    根据查询条件获取指定前xx条数,支持排序

    1. // sort by "field" ascending and "test" descending
    2. var query = {};
    3. var sort = {field: 'asc', test: -1 };
    4. Top.top(30, query, sort , function(err, tops){
    5. if(err){
    6. console.dir(err);
    7. }
    8. // console.dir(tops.length);
    9. assert.equal(tops.length == 30, true);
    10. done();
    11. });

    更改pagesize

    1. Top.pagesize = 25;
    2. Top.top(function(err, tops){
    3. if(err){
    4. console.dir(err);
    5. // console.dir(tops.length);
    6. assert.equal(tops.length == 25, true);
    7. done();
    8. });

    pageByLastId

    根据id直接返回,长度看第二个参数,下面的例子是50

    1. Top.pageByLastId(one._id, 50, function(err, new_tops){

    根据id直接返回,长度看第二个参数,下面的例子是50,不带带有排序条件

    根据id直接返回,长度看第二个参数,下面的例子是50,带有排序条件,created_at是升序

    1. Top.pageByLastId(one._id, 100, {"username" : "fixture-user-41"}, {created_at:'asc'}, function(err, new_tops){

    mongoosedao + promisifyAll

    1. var mongoose = require('mongoose');
    2. var Schema = mongoose.Schema;
    3. var MongooseDao = require('mongoosedao');
    4. var contactSchema = new Schema(
    5. {
    6. "name":"String",
    7. "address":"String",
    8. "tel":"String",
    9. "owner_id":"String",
    10. "created_at": {
    11. type: Date,
    12. "default": Date.now()
    13. }
    14. }
    15. );
    16. var Contact = mongoose.model('Contact', contactSchema);
    17. var ContactDao = new MongooseDao(Contact);
    18. var Promise = require("bluebird");
    19. Promise.promisifyAll(Contact);
    20. Promise.promisifyAll(Contact.prototype);
    21. Promise.promisifyAll(ContactDao);
    22. module.exports = ContactDao;

    注意,为了方便直接使用模型,给模型和dao都增加了promisifyAll方法,核心代码如下

    1. var Promise = require("bluebird");
    2. Promise.promisifyAll(Contact);
    3. Promise.promisifyAll(Contact.prototype);
    4. Promise.promisifyAll(ContactDao);

    User.model is a mongoose model. You can do all as mongoose model。

    more features

    • statics
    • methods
    • pre or post hook
    • aggregation

    比如直接扩展方法

    1. var mongoose = require('mongoose');
    2. var Schema = mongoose.Schema;
    3. var Promise = require('bluebird');
    4. var User = require('../app/models/user');
    5. User.schema.statics.find_by_openid = function(openid, cb) {
    6. console.log('find_by_openid...')
    7. };
    8. // 此处必须要重置一下model
    9. User = mongoose.model('User', User.schema);
    10. var MongooseDao = require('mongoosedao');
    11. var UserDao = new MongooseDao(Test);
    12. UserDao.model.find_by_openid({}, function(err,docs){
    13. // console.dir(docs);
    14. });

    当然我们更推荐的是在model定义上直接加

    只要mongoose支持的,使用mongoosedao都可以完成,甚至更好。

    总结

    mongoosedao是对mongoose操作的约定,提供了更方便的api封装而已,结合bluebird的promisifyAll可以非常好的满足我们日常的业务需求。