首页 文章

如何组织使用sequelize的节点应用程序?

提问于
浏览
109

我正在寻找使用sequelize ORM的示例nodejs应用程序 .

我主要担心的是,如果这些模型由于require()依赖性循环而彼此之间存在复杂的关系,那么几乎不可能在单独的js文件中定义模型 . 也许人们将所有模型定义在一个非常长的文件中?

我主要感兴趣的是如何定义模型并在整个应用程序中使用 . 我想有一些验证,我自己做的是做事的“好”方式 .

10 回答

  • 2

    我创建了一个包 sequelize-connect 来帮助人们处理这个问题 . 它遵循Sequelize建议的惯例:http://sequelize.readthedocs.org/en/1.7.0/articles/express/

    此外,就接口而言,它的功能更像Mongoose . 它允许您指定模型所在的一组位置,还允许您定义自定义匹配函数以匹配模型文件 .

    用法基本上是这样的:

    var orm = require('sequelize-connect');
    
    orm.discover = ["/my/model/path/1", "/path/to/models/2"];      // 1 to n paths can be specified here
    orm.connect(db, user, passwd, options);                        // initialize the sequelize connection and models
    

    然后你就可以像这样访问模型和续集:

    var orm       = require('sequelize-connect');
    var sequelize = orm.sequelize;
    var Sequelize = orm.Sequelize;
    var models    = orm.models;
    var User      = models.User;
    

    希望这有助于某人 .

  • 113

    您还可以使用依赖注入,为此提供优雅的解决方案 . 这是一个https://github.com/justmoon/reduct

  • 9

    我开始在Express.js应用程序中使用Sequelize . 很快就遇到了你所描述的性质问题 . 也许我对Sequelize并不十分了解,但对我而言,做事不仅仅是从一张 table 中选择并不是很方便 . 通常你会在两个或多个表中使用select,或者在纯SQL中使用union,你必须运行单独的查询,并且由于Node的异步性质,它只是增加了复杂性 .

    因此我放弃了使用Sequelize . 此外,我正在从模型中使用从数据库中获取的任何数据进行切换 . 在我看来,抽象获取数据更好 . 原因是 - 假设您不仅使用MySQL(在我的情况下,我并排使用MySQL和MongoDB),但您可以从任何数据提供者和任何传输方法获取数据,例如SQL,无SQL,文件系统,外部API,FTP,SSH等 . 如果您尝试在模型中完成所有这些操作,最终会创建难以升级和调试的复杂且难以理解的代码 .

    现在你要做的是让模型从知道在哪里以及如何获取它的层获取数据,但是你的模型只使用API方法,例如 fetchsavedelete 等 . 在此层中,您具有特定数据提供程序的特定实现 . 例如 . 您可以从本地计算机上的PHP文件或Facebook API或Amazon AWS或远程HTML文档等请求某些数据 .

    PS 其中一些想法是从Cloud9借用Architect:http://events.yandex.ru/talks/300/

  • 24

    我把它设置为Farm和文档描述 .

    但我有另外一个问题,在我的实例中,我将附加到每个函数中的模型的方法和类方法,我需要索引文件来获取其他数据库对象 .

    通过使所有型号都可以访问它来解决它 .

    var Config = require('../config/config');
    
     var fs = require('fs');
    var path = require('path');
    var Sequelize = require('sequelize');
    var _ = require('lodash');
    var sequelize;
    var db = {};
    
    var dbName, dbUsername, dbPassword, dbPort, dbHost;
    // set above vars
    
    var sequelize = new Sequelize(dbName, dbUsername, dbPassword, {
    dialect: 'postgres', protocol: 'postgres', port: dbPort, logging: false, host: dbHost,
      define: {
        classMethods: {
            db: function () {
                        return db;
            },
            Sequelize: function () {
                        return Sequelize;
            }
    
        }
      }
    });
    
    
    fs.readdirSync(__dirname).filter(function(file) {
       return (file.indexOf('.') !== 0) && (file !== 'index.js');
    }).forEach(function(file) {
      var model = sequelize.import(path.join(__dirname, file));
      db[model.name] = model;
    });
    
    Object.keys(db).forEach(function(modelName) {
      if ('associate' in db[modelName]) {
          db[modelName].associate(db);
      }
    });
    
    module.exports = _.extend({
      sequelize: sequelize,
      Sequelize: Sequelize
    }, db);
    

    并在模型文件中

    var classMethods = {
      createFromParams: function (userParams) {
        var user = this.build(userParams);
    
        return this.db().PromoCode.find({where: {name: user.promoCode}}).then(function (code) {
            user.credits += code.credits;
                    return user.save();
        });
      }
    
    };
    
    module.exports = function(sequelize, DataTypes) {
      return sequelize.define("User", {
      userId: DataTypes.STRING,
    }, {  tableName: 'users',
        classMethods: classMethods
     });
    };
    

    我只对类方法执行此操作,但您也可以对实例方法执行相同的操作 .

  • 90

    您可以使用 sequelize.import http://sequelizejs.com/documentation#models-import从其他文件导入模型

    这样你可以有一个单例模块用于sequelize,然后加载所有其他模型 .

    实际上这个答案与user1778770的答案非常相似 .

  • 4

    我正在寻找使用sequelize ORM的示例nodejs应用程序 .

    您可能有兴趣查看PEAN.JS样板解决方案 .

    PEAN.JS是一个全栈JavaScript开源解决方案,它为PostgreSQL,Node.js,Express和基于AngularJS的应用程序提供了坚实的起点 .

    PEAN项目是MEAN.JS项目的一个分支(不要与MEAN.IO或通用MEAN堆栈混淆) .

    PEAN用PostgreSQL和Sequelize替换MongoDB和Mongoose ORM . MEAN.JS项目的主要好处是它为具有许多移动部件的堆栈提供的组织 .

  • 1

    短篇小说

    在这种情况下的技巧不是初始化文件中的模型,而只是为其初始化提供必要的信息,让集中模块负责模型设置和实例化 .

    所以步骤是:

    • 拥有多个模型文件,其中包含有关模型的数据,如字段,关系和选项 .

    • 有一个单例模块,可以加载所有这些文件并设置所有模型类和关系 .

    • 在app.js文件中设置单例模块 .

    • 从模型文件中的单例模块 do not 获取模型类,使用 require ,从单例加载模型 .

    更长的故事

    以下是此解决方案的更详细说明以及相应的源代码:

    http://jeydotc.github.io/blog/2012/10/30/EXPRESS-WITH-SEQUELIZE.html

    编辑:这是一个非常古老的答案! (阅读信息)

    It's old and limited in many ways!

    • First ,正如评论中提到的@jinglesthula(我也经历过) - 需要这些文件存在问题 . 这是因为 requirereaddirSync 的工作方式不同!

    • Second - 你在关系中是 very 限制 - 代码不为这些关联提供选项,因此你需要 UNABLE 来创建 belongsToMany ,因为它需要 through 属性 . 您可以创建最基本的关联 .

    • Third - 模特关系非常有限!如果你仔细阅读代码,你会看到关系是 Object 而不是 Array ,所以如果你想使 more than one 关联相同(比如有两次 belongsTo ) - 你就不能!

    • Fourth - 你不需要那个单身人士的东西 . nodejs中的每个模块本身都是单例,因此所有这些都是无缘无故的 .

    您应该看到Farm 's answer! (The link to the article is broken, but I' ll使用来自sequelize的官方样本修复它:https://github.com/sequelize/express-example/blob/master/models/index.js - 您可以浏览整个项目以了解正在发生的事情) .

    附:我正在编辑这篇文章,因为它如此受欢迎,以至于人们甚至都看不到任何新的答案(正如我所做的那样) .

    Edit: 刚刚将链接更改为同一帖子的副本,但是在Github页面中

  • 1

    样本模型续集

    'use strict';
    const getRole   = require('../helpers/getRole')
    const library   = require('../helpers/library')
    const Op        = require('sequelize').Op
    
    module.exports = (sequelize, DataTypes) => {
      var User = sequelize.define('User', {
        AdminId: DataTypes.INTEGER,
        name: {
          type: DataTypes.STRING,
          validate: {
            notEmpty: {
              args: true,
              msg: 'Name must be filled !!'
            },
          }
        },
        email: {
          type: DataTypes.STRING,
          validate: {
            notEmpty: {
              args: true,
              msg: 'Email must be filled !!'
            },
            isUnique: function(value, next) {
              User.findAll({
                where:{
                  email: value,
                  id: { [Op.ne]: this.id, }
                }
              })
              .then(function(user) {
                if (user.length == 0) {
                  next()
                } else {
                  next('Email already used !!')
                }
              })
              .catch(function(err) {
                next(err)
              })
            }
          }
        },
        password: {
          type: DataTypes.STRING,
          validate: {
            notEmpty: {
              args: true,
              msg: 'Password must be filled !!'
            },
            len: {
              args: [6, 255],
              msg: 'Password at least 6 characters !!'
            }
          }
        },
        role: {
          type: DataTypes.INTEGER,
          validate: {
            customValidation: function(value, next) {
              if (value == '') {
                next('Please choose a role !!')
              } else {
                next()
              }
            }
          }
        },
        gender: {
          type: DataTypes.INTEGER,
          validate: {
            notEmpty: {
              args: true,
              msg: 'Gender must be filled !!'
            },
          }
        },
        handphone: {
          type: DataTypes.STRING,
          validate: {
            notEmpty: {
              args: true,
              msg: 'Mobile no. must be filled !!'
            },
          }
        },
        address: DataTypes.TEXT,
        photo: DataTypes.STRING,
        reset_token: DataTypes.STRING,
        reset_expired: DataTypes.DATE,
        status: DataTypes.INTEGER
      }, {
        hooks: {
          beforeCreate: (user, options) => {
            user.password = library.encrypt(user.password)
          },
          beforeUpdate: (user, options) => {
            user.password = library.encrypt(user.password)
          }
        }
      });
    
      User.prototype.check_password = function (userPassword, callback) {
        if (library.comparePassword(userPassword, this.password)) {
          callback(true)
        }else{
          callback(false)
        }
      }
    
      User.prototype.getRole = function() {
        return getRole(this.role)
      }
    
      User.associate = function(models) {
        User.hasMany(models.Request)
      }
    
      return User;
    };
    

  • 0

    SequelizeJS has a article在他们的网站上解决了这个问题 .

    链接已损坏,但您可以找到工作示例项目here并进行浏览 . 请参阅上面编辑的答案,了解为什么这是更好的解决方案 .

    文章摘录:

    • models / index.js

    此文件的想法是配置与数据库的连接并收集所有模型定义 . 一切就绪后,我们将调用每个模型上关联的方法 . 此方法可用于将模型与其他模型相关联 .

    var fs        = require('fs')
            , path      = require('path')
            , Sequelize = require('sequelize')
            , lodash    = require('lodash')
            , sequelize = new Sequelize('sequelize_test', 'root', null)
            , db        = {} 
    
          fs.readdirSync(__dirname)
            .filter(function(file) {
              return (file.indexOf('.') !== 0) && (file !== 'index.js')
            })
            .forEach(function(file) {
              var model = sequelize.import(path.join(__dirname, file))
              db[model.name] = model
            })
    
          Object.keys(db).forEach(function(modelName) {
            if (db[modelName].options.hasOwnProperty('associate')) {
              db[modelName].options.associate(db)
            }
          })
    
          module.exports = lodash.extend({
            sequelize: sequelize,
            Sequelize: Sequelize
          }, db)
    
  • 1

    我遵循官方指南:http://sequelizejs.com/heroku,它有一个模型文件夹,在单独的文件中设置每个模块,并有一个索引文件来导入它们并设置它们之间的关系 .

相关问题