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

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

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

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

84567 次浏览

短篇小说

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

所以步骤是:

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

说来话长

下面是这个解决方案的更详细的描述和相应的源代码:

Http://jeydotc.github.io/blog/2012/10/30/express-with-sequelize.html

编辑: 这是一个非常古老的答案

它在很多方面都是古老而有限的!

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

  • 第二个 -你是 非常限制在关系-代码不提供 选择到这些关联,所以你是 不能创建 belongsToMany,因为它需要 through属性。你可以做最基本的按钮。

  • 第三 -你在模型关系方面非常有限!如果你仔细阅读代码,你会发现关系是一个 反对而不是 数组,所以如果你想使 不止一个关联的同一类型(如有两次 belongsTo)-你不能!

  • 第四个 -你不需要那个单例模式的东西。Nodejs 中的每个模块本身都是单例的,因此所有这些都会毫无理由地变得非常复杂。

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

附言。 我正在编辑这篇文章,因为它是如此的反对,以至于人们甚至不会看到任何新的答案(就像我一样)。

编辑: 只是改变了链接到同一篇文章的副本,但在 Github 页面

我开始在 Express.js 应用程序中使用 Sequelize。很快就遇到了你所描述的自然问题。也许我并不完全理解 Sequelize,但是对我来说,除了从一个表中选择之外做其他事情并不真正方便。在通常情况下,从两个或多个表中使用 select,或者在纯 SQL 中使用联合,则必须运行单独的查询,由于 Node 的异步特性,这只会增加复杂性。

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

现在您想要做的是让模型从一个知道从哪里以及如何获取数据的层获取数据,但是您的模型只使用 API 方法,例如 fetchsavedelete等。在这一层中,您有针对特定数据提供程序的特定实现。例如,您可以从本地机器上的 PHP 文件、 Facebook API、 Amazon AWS 或远程 HTML 文档等请求某些数据。

其中一些想法是由 云9建筑师那里借鉴而来的: http://events.yandex.ru/talks/300/

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

这样,您可以有一个用于序列化的单例模块,然后加载所有其他模型。

实际上,这个答案与用户1778770的答案非常相似。

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

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

链接中断,但是您可以找到工作示例项目 给你并浏览它。参见上面编辑过的答案,看看为什么这是一个更好的解决方案。

摘自文章:

  • Model/index.js

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

          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)
    

我把它设置成农场,文件描述了。

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

通过让所有模型都可以访问,解决了这个问题。

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

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

我已经创建了一个包 Rel = “ noReferrer”> Sequelize-connect < a href = “ https://www.npmjs.com/package/Sequelize-connect”rel = “ noReferrer”> Sequelize-connect 来帮助人们处理这个问题

此外,在接口方面,它的功能也有点像 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;

希望这能帮到别人。

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

您可能对 PEAN.JS 样板解决方案感兴趣。

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

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

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

你也可以使用一个依赖注入来解决这个问题

样本模型序列化

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