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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12487416/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 16:19:06  来源:igfitidea点击:

How to organize a node app that uses sequelize?

node.jsexpresssequelize.js

提问by mkoryak

I am looking for an example nodejs app that uses the sequelize ORM.

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

My main concern is that it seems next to impossible to define your models in separate js files if those models have complex relationships to one another because of require() dependency loops. Maybe people define all their models in one file that is very very long?

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

I am mainly interested in how the models are defined and use through out the app. I would like to have some validation that what i am doing on my own is the "good" way to do things.

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

采纳答案by user1778770

The short story

简短的故事

The trick in this case is not to initialize the model inthe file but just to provide the necesary information for its initialization and let a centralized module take care of the models setup and instantiation.

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

So the steps are:

所以步骤是:

  • Have several Model files with data about the model, like fields, relationships and options.
  • Have a singleton module which loads all those files and setup all the model classes and relationships.
  • Setup your singleton module at the app.js file.
  • Get the model classes from the singleton module do notuse requireon your model files, load the models from the singleton instead.
  • 有多个模型文件,其中包含有关模型的数据,例如字段、关系和选项。
  • 有一个加载所有这些文件并设置所有模型类和关系的单例模块。
  • 在 app.js 文件中设置你的单例模块。
  • 从单例模块中获取模型类不要用于require您的模型文件,而是从单例加载模型。

The longer story

更长的故事

Here is a more detailed description of this solution with the corresponding source code:

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

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

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

EDIT: This is a very old answer! (read down for info)

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

It's old and limited in many ways!

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

  • First, as @jinglesthula mentioned in comments (and I experienced it too) - there are problems with requiring those files. It's because requiredoesn't work the same way as readdirSync!

  • Second- you are verylimited in relations - the code doesn't provide optionsto those associations so you are UNABLEto create belongsToManyas it needs throughproperty. You can make the most basic assocs.

  • Third- you are very limited in model relations! If you read closely the code, you will see that relations is an Objectinstead of an Array, so if you want to make more than oneassociations of the same type (like having two times belongsTo) - you cannot!

  • Fourth- You don't need that singleton thingy. Every module in nodejs is singleton by itself, so all this makes is pretty complex for no reason.

  • 首先,正如@jinlesthula 在评论中提到的(我也经历过) - 要求这些文件存在问题。这是因为requirereaddirSync!

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

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

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

You should see Farm's answer! (The link to the article is broken, but I'll fix it with this official sample from sequelize: https://github.com/sequelize/express-example/blob/master/models/index.js- you can browse the whole project to get an idea of what's going on).

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

p.s. I'm editing this post as it's so upvoted that people won't even see any new answers (as I did).

ps 我正在编辑这篇文章,因为它被点赞,以至于人们甚至看不到任何新答案(就像我所做的那样)。

Edit:Just changed the link to a copy of the same post, but in a Github Page

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

回答by Farm

SequelizeJS has a articleon their website which solves this problem.

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

Link is broken, but you can find the working sample project hereand browse it. See edited answer above to see why this is a better solution.

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

Extract from article:

文章摘录:

  • models/index.js

    The idea of this file is to configure a connection to the database and to collect all Model definitions. Once everything is in place, we will call the method associated on each of the Models. This method can be used to associate the Model with others.

          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)
    
  • 模型/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)
    

回答by jspizziri

I've create a package sequelize-connectto help people deal with this issue. It follows the Sequelize suggested convention here: http://sequelize.readthedocs.org/en/1.7.0/articles/express/

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

Additionally it also functions a bit more like Mongoose in terms of its interface. It allows you to specify a set of locations where your models are located and also allows you to define a custom matching function to match your model files.

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

The usage is basically like this:

用法基本上是这样的:

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

Then you can access the models and sequelize like so:

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

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

Hopefully this helps someone out.

希望这可以帮助某人。

回答by mvbl fst

I started using Sequelize in Express.js app. Soon enough ran into issues of the nature you're describing. Maybe I did not quite understand Sequelize, but to me doing things more than just selecting from one table wasn't really convenient. And where ordinarily you would use select from two or more tables, or a union in pure SQL, you would have to run separate queries, and with the async nature of Node it's just added complexity.

我开始在 Express.js 应用程序中使用 Sequelize。很快就遇到了你所描述的性质的问题。也许我不太了解 Sequelize,但对我来说,除了从一张表中选择之外,做更多的事情并不是很方便。在通常情况下,您将从两个或多个表中选择,或在纯 SQL 中使用联合,您将不得不运行单独的查询,而 Node 的异步性质只会增加复杂性。

Therefore I moved away from using Sequelize. Moreover I am switching from using ANY data fetching from DB in the models. In my opinion it is better to abstract getting data completely. And reasons are - imagine that you don't just use MySQL (in my case, I use MySQL and MongoDB side by side), but you can get your data from any data provider and any transport method, e.g. SQL, no-SQL, filesystem, external API, FTP, SSH etc. If you tried to do all of it in the models, you would eventually create complex and hard to understand code that would be hard to upgrade and debug.

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

Now what you want to do is to have models get data from a layer that knows where and how to get it, but your models only use API methods, e.g. fetch, save, deleteetc. And inside this layer you have specific implementations for specific data providers. E.g. you can request certain data from a PHP file on a local machine or from Facebook API or from Amazon AWS or from remote HTML document, etc.

现在,你想要做的是有机型从知道在哪里以及如何获得它一个层中获取数据,但您的模型只使用API的方法,例如fetchsavedelete等这层内你有具体的数据提供商的具体实现。例如,您可以从本地机器上的 PHP 文件、Facebook API、亚马逊 AWS 或远程 HTML 文档等请求某些数据。

PSsome of these ideas were borrowed from Architectby Cloud9: http://events.yandex.ru/talks/300/

PS一些想法是从借来的设计师通过CLOUD9http://events.yandex.ru/talks/300/

回答by jacob

I set it up as Farm and the documentation describe.

我将它设置为 Farm 和文档描述。

But I was having the additonal problem that in my instance methods and class methods that I would attach to the models in each function I would need to require the index file to get a hold of other database objects.

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

Solved it by making them accessible to all models.

通过使所有模型都可以访问它们来解决它。

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);

And in the model file

并在模型文件中

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

I only did this for the class methods but you could also do the same thing for instance methods.

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

回答by Ron

I am following the official guide: http://sequelizejs.com/heroku, which has a models folder, set up each module in separate files, and have a index file to import them and set the relationship among them.

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

回答by Muhammad Arief Trimanda

Sample model sequelize

样本模型续集

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



回答by mg1075

I am looking for an example nodejs app that uses the sequelize ORM.

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

You might be interested in looking at the PEAN.JS boilerplate solution.

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

PEAN.JS is a full-stack JavaScript open-source solution, which provides a solid starting point for PostgreSQL, Node.js, Express, and AngularJS based applications.

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

The PEAN project is a fork of the MEAN.JS project (not to be confused with MEAN.IO or the genericMEAN stack).

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

PEAN replaces MongoDB and the Mongoose ORM with PostgreSQL and Sequelize. A primary benefit of the MEAN.JS project is the organization it provides to a stack that has many moving pieces.

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

回答by natrixnatrix89

You can import models from other files with sequelize.importhttp://sequelizejs.com/documentation#models-import

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

That way you can have one singleton module for sequelize, which then loads all the other models.

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

Actually this answer is quite similar to user1778770`s answer.

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

回答by Vahe Hovhannisyan

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

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