04月11, 2016

ThinkJS 项目里如何使用 Mongoose

ThinkJS 里内置的 ORM 可以很方便的操作关系型数据库和文档型数据库,支持:Mysql,SQLite,PostgreSQL,Mongo 等。如果内置的 ORM 不能满足项目的需求,那么也可以集成第三方的 ORM,如:Mongoose,Waterline 等。本文就来聊聊如何在 ThinkJS 里集成 Mongoose。

关于 Mongoose

Mongoose 是一个专门用来操作 Mongo 的 ORM,提供了很多非常有用的方法。可以通过 npm install mongoose 命令来安装 Mongoose,Mongoose 详细文档请见: http://mongoosejs.com/docs/guide.html

项目里可以直接引入 Mongoose,然后根据官方文档来使用,但这种方式下开发会比较麻烦,因为没法使用 ThinkJS 里内置的模型类、自动实例化和自动传入模型配置等功能了。

ThinkJS 模型与 Mongoose 的差异

ThinkJS 的模型是一个类,实例化的时候会传入模型名称和连接 Mongo 的配置,基类大致代码如下:

export default class {
    // name 为传入的模型名称,没有传入的话会自动分析当前的文件名作为模型名
   // config 为连接 Mongo 的配置
    constructor(name, config){
        this.name = name;
        this.config = config;
    }
}

而连接 Mongo 是通过 Mongo Socket 这个 Adapter 来完成的,后续操作都是等拿到 Socket Connection 后进行。

Mongoose 里是创建连接,然后定义 schema 和创建模型,使用时实例化模型。如果有多个配置连接的话,通过 createConnection 方法来创建连接。

var mongoose = require("mongoose")
  , Schema = mongoose.Schema

var personSchema = Schema({
  _id     : Number,
  name    : String,
  age     : Number,
  stories : [{ type: Schema.Types.ObjectId, ref: "Story" }]
});

var storySchema = Schema({
  _creator : { type: Number, ref: "Person" },
  title    : String,
  fans     : [{ type: Number, ref: "Person" }]
});

所以可以通过包装将 Mongoose 的格式转成 ThinkJS 的格式。

如何包装

"use strict";

import mongoose from "mongoose";

/**
 * model
 */
export default class extends think.base {
  /**
   * schema
   * @type {Object}
   */
  schema = {};
  /**
   * model instance
   * @type {[type]}
   */
  _model = null;
  /**
   * constructor
   * @param  {[type]} name   [description]
   * @param  {Object} config [description]
   * @return {[type]}        [description]
   */
  constructor(name, config = {}){
    super();
    if(think.isObject(name)){
      config = name;
      name = "";
    }
    this.name = name;
    this.config = think.parseConfig(config);
  }
  /**
   * 创建连接
   * @return {[type]} [description]
   */
  getConnection(){
    let user = "";
    if(this.config.user){
      user = this.config.user + ":" + this.config.password + "@";
    }
    let host = this.config.host || "127.0.0.1";
    let port = this.config.port || 27017;
    let str = `mongodb://${user}${host}:${port}/${this.config.database}`;

    return mongoose.createConnection(str);
  }
  /**
   * 获取 Mongoose 里的 Model
   * @return {[type]} [description]
   */
  getModel(){
    if(!this._model){
      let connection = this.getConnection();
      this._model = connection.model(this.name, new mongoose.Schema(this.schema));
    }
    return this._model;
  }
}

通过上面包装的方式后,可以通过 getModel 方法获取 Mongoose 里的模型,然后就可以对其实例化进行操作了。如:

export default class extends think.controller.base {
  /**
   * index action
   * @return {Promise} []
   */
  async indexAction(){
    let instance = this.model("user");
    let model = instance.getModel();
    let ret = await model.create({
      username: "welefen"
    });

    let data = await model.find({}).exec();
    console.log(data)

    //auto render template file index_index.html
    return this.display();
  }
}

实际项目中,建议将上面的包装放在 model/base.js 里,其他模型文件继承该类。 控制器里通过 getModel 方法获取模型,然后实例化并调用方法,也可以将这些逻辑封装在模型中。如:

// model/use.js

import Base from "./base";

export default class extends Base {
    schema = {
        username: String
    };
    findData(where = {}){
        let Model = this.getModel();
        return Model.find(where).exec();
    }
    addData(data = {}){
        let Model = this.getModel();
        return model.create(data);
    }
}

这样就可以通过 findData 方法来查询数据,addData 方法来添加数据了。

本文链接:http://welefen.com/post/use-mongoose-in-thinkjs.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。