ThinkJS 项目里如何使用 Mongoose

1284次阅读  |  发布于5年以前

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 方法来添加数据了。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8