131

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

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

我主要对如何在整个应用程序中定义和使用模型感兴趣。我想验证一下我自己做的事情是“好”的做事方式。

4

10 回答 10

129

短篇小说

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

所以步骤是:

  • 有几个模型文件,其中包含有关模型的数据,例如字段、关系和选项。
  • 有一个单例模块,它加载所有这些文件并设置所有模型类和关系。
  • 在 app.js 文件中设置你的单例模块。
  • 从单例模块获取模型类,不要在模型文件上使用require,而是从单例加载模型。

更长的故事

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

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

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

它在很多方面都是旧的和有限的!

  • 首先,正如@jinglesthula 在评论中提到的(我也经历过) - 需要这些文件存在问题。这是因为它的require工作方式与readdirSync!

  • 其次-您的关系非常有限-代码不为这些关联提供选项,因此您无法belongsToMany根据需要创建through属性。您可以制作最基本的 assocs。

  • 第三- 你的模型关系非常有限!如果你仔细阅读代码,你会发现关系是一个Object而不是Array,所以如果你想创建多个相同类型的关联(比如有两次belongsTo) - 你不能!

  • 第四- 你不需要那个单身的东西。nodejs 中的每个模块本身都是单例的,所以这一切都无缘无故地变得非常复杂。

你应该看到农场的答案!(文章的链接已损坏,但我将使用 sequelize 的官方示例修复它:https ://github.com/sequelize/express-example/blob/master/models/index.js - 你可以浏览整个项目以了解正在发生的事情)。

ps 我正在编辑这篇文章,因为它的投票率很高,以至于人们甚至都看不到任何新的答案(就像我一样)。

编辑:刚刚将链接更改为同一篇文章的副本,但在 Github 页面中

于 2012-10-31T03:52:28.540 回答
96

SequelizeJS 在他们的网站上有一篇文章解决了这个问题。

链接已损坏,但您可以在此处找到工作示例项目并浏览它。请参阅上面的编辑答案,了解为什么这是一个更好的解决方案。

文章摘录:

  • 模型/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)
    
于 2013-12-15T03:54:36.673 回答
29

我创建了一个包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;

希望这可以帮助某人。

于 2015-01-30T12:42:18.360 回答
8

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

因此我不再使用 Sequelize。此外,我正在从模型中使用从数据库中获取的任何数据切换。在我看来,最好完全抽象获取数据。原因是 - 假设您不只是使用 MySQL(在我的情况下,我同时使用 MySQL 和 MongoDB),但您可以从任何数据提供者和任何传输方法获取数据,例如 SQL、no-SQL、文件系统、外部 API、FTP、SSH 等。如果你试图在模型中完成所有这些,你最终会创建复杂且难以理解的代码,这些代码很难升级和调试。

现在您要做的是让模型从知道从何处以及如何获取数据的层获取数据,但是您的模型仅使用 API 方法,例如fetch,等。在该层内savedelete您有特定数据提供者的特定实现。例如,您可以从本地机器上的 PHP 文件或 Facebook API 或 Amazon AWS 或远程 HTML 文档等请求某些数据。

PS其中一些想法是从Cloud9的建筑师那里借来的:http: //events.yandex.ru/talks/300/

于 2012-10-31T04:05:29.207 回答
5

我将其设置为 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
 });
};

我只对类方法这样做,但你也可以对实例方法做同样的事情。

于 2014-05-29T19:24:51.810 回答
2

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

于 2013-08-06T10:12:23.900 回答
2

样本模型续集

'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;
};


于 2018-01-31T17:08:47.290 回答
1

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

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

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

于 2013-06-13T08:32:08.997 回答
1

我正在寻找一个使用 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 项目的一个主要好处是它为具有许多移动部件的堆栈提供的组织。

于 2016-03-23T03:54:26.553 回答
0

You can also use a dependency injection which provides an elegant solution to this. Here's one https://github.com/justmoon/reduct

于 2016-10-12T23:57:15.430 回答