Je suis à la recherche d'un exemple d'application Nodejs utilisant l'ORM séquestre.
Ma principale préoccupation est qu'il semble presque impossible de définir vos modèles dans des fichiers js distincts si ces modèles ont des relations complexes les unes par rapport aux autres en raison de boucles de dépendance require (). Peut-être que les gens définissent tous leurs modèles dans un fichier qui est très très long?
Je suis principalement intéressé par la façon dont les modèles sont définis et utilisés dans l'application. J'aimerais avoir la confirmation que ce que je fais seul est la "bonne" façon de faire les choses.
Dans ce cas, l’astuce n’est pas d’initialiser le modèle in du fichier, mais de fournir les informations nécessaires à son initialisation et de laisser un module centralisé se charger de la configuration et de l’instanciation des modèles.
Les étapes sont donc les suivantes:
require
sur vos fichiers de modèle; chargez les modèles à partir du singleton à la place.Voici une description plus détaillée de cette solution avec le code source correspondant:
http://jeydotc.github.io/blog/2012/10/30/EXPRESS-WITH-SEQUELIZE.html
C'est vieux et limité à bien des égards!
First, comme indiqué dans les commentaires de @jinglesthula (et je l'ai aussi expérimenté) - il est difficile d'exiger ces fichiers. C'est parce que require
ne fonctionne pas de la même manière que readdirSync
!
Deuxième - vous êtes très limité dans les relations - le code ne fournit pas options à ces associations, vous êtes donc INCAPABLE de créer belongsToMany
car il a besoin de through
propriété. Vous pouvez faire les assocs les plus basiques.
Troisième - vous êtes très limité dans les relations de modèle! Si vous lisez attentivement le code, vous verrez que relations est un Object au lieu d'un Array, donc si vous voulez faire plus d'une association du même type (comme si vous aviez deux fois belongsTo
) - vous ne pouvez pas!
Quatrième - Vous n'avez pas besoin de ce singleton. Chaque module de nodejs est singleton par lui-même, donc tout ceci est complexe sans raison.
Vous devriez voir la réponse de Farm! (Le lien vers l'article est cassé, mais je vais le réparer avec cet échantillon officiel de sequelize: https://github.com/sequelize/express-example/blob/master/models/index.js - vous pouvez parcourir l’ensemble du projet pour avoir une idée de ce qui se passe).
p.s . J'édite ce billet car il est tellement voté que les gens ne verront même pas de nouvelles réponses (comme je l'ai fait).
Edit: vient de changer le lien en une copie du même message, mais dans une page Github
SequelizeJS a un article sur son site internet qui résout ce problème.
Le lien est rompu, mais vous pouvez trouver le projet exemple en cours ici et le parcourir. Voir la réponse modifiée ci-dessus pour voir pourquoi il s'agit d'une meilleure solution.
Extrait de l'article:
modèles/index.js
L'idée de ce fichier est de configurer une connexion à la base de données et de collecter toutes les définitions de modèle. Une fois que tout est en place, nous appellerons la méthode associée à chacun des modèles. Cette méthode peut être utilisée pour associer le modèle à d’autres.
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)
J'ai créé un package sequelize-connect pour aider les gens à faire face à ce problème. Voici la convention suggérée par Sequelize: http://sequelize.readthedocs.org/fr/1.7.0/articles/express/
De plus, il fonctionne un peu plus comme Mongoose en termes d’interface. Il vous permet de spécifier un ensemble d'emplacements où se trouvent vos modèles et vous permet également de définir une fonction de correspondance personnalisée correspondant à vos fichiers de modèle.
L'utilisation est fondamentalement comme ceci:
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
Ensuite, vous pouvez accéder aux modèles et vous séquencer comme suit:
var orm = require('sequelize-connect');
var sequelize = orm.sequelize;
var Sequelize = orm.Sequelize;
var models = orm.models;
var User = models.User;
Espérons que cela aide quelqu'un.
J'ai commencé à utiliser Sequelize dans l'application Express.js. Bientôt, assez de problèmes rencontrés dans la nature que vous décrivez. Je ne comprenais peut-être pas vraiment Sequelize, mais pour moi, faire plus que simplement choisir une table ne me convenait pas vraiment. Et là où vous utiliseriez habituellement select parmi deux tables ou plus, ou une union en SQL pur, vous auriez à exécuter des requêtes distinctes, et avec la nature asynchrone de Node, cela ne fait qu'ajouter à la complexité.
Par conséquent, je me suis écarté de l'utilisation de Sequelize. De plus, je remplace l'utilisation de TOUT type de récupération de données à partir de la base de données dans les modèles. À mon avis, il est préférable d’abstraire complètement l’obtention de données. Et les raisons en sont: imaginez que vous n'utilisez pas simplement MySQL (dans mon cas, j'utilise MySQL et MongoDB côte à côte), mais vous pouvez obtenir vos données auprès de n'importe quel fournisseur de données et de toute méthode de transport, par exemple. SQL, no-SQL, système de fichiers, API externe, FTP, SSH, etc. Si vous essayez de tout faire dans les modèles, vous allez éventuellement créer du code complexe et difficile à comprendre qui sera difficile à mettre à niveau et à déboguer.
Désormais, vous voulez que les modèles obtiennent les données d'une couche qui sait où et comment les obtenir, mais vos modèles utilisent uniquement des méthodes API, par exemple. fetch
, save
, delete
etc. Et à l'intérieur de cette couche, vous avez des implémentations spécifiques pour des fournisseurs de données spécifiques. Par exemple. vous pouvez demander certaines données à partir d'un fichier PHP sur une machine locale ou à partir de l'API Facebook, d'Amazon AWS ou d'un document HTML distant, etc.
PS certaines de ces idées ont été empruntées à Architecte par Cloud9: http://events.yandex.ru/talks/300/
Je l'ai configuré comme ferme et la documentation décrit.
Mais j’avais le problème supplémentaire que j’attacherais dans mes méthodes d’instance et de classe aux modèles de chaque fonction le fichier d’index pour pouvoir accéder à d’autres objets de base de données.
Résolu en les rendant accessibles à tous les modèles.
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);
Et dans le fichier modèle
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
});
};
Je l'ai fait uniquement pour les méthodes de classe, mais vous pouvez également faire la même chose pour les méthodes d'instance.
Je suis le guide officiel: http://sequelizejs.com/heroku , qui contient un dossier de modèles, configure chaque module dans des fichiers distincts et dispose d’un fichier d’index pour les importer et définir la relation entre eux.
Exemple de modèle 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;
};
Je suis à la recherche d'un exemple d'application Nodejs utilisant l'ORM séquestre.
Vous pourriez être intéressé par la solution standard de PEAN.JS.
PEAN.JS est une solution open source JavaScript à pile complète qui constitue un solide point de départ pour les applications basées sur PostgreSQL, Node.js, Express et AngularJS.
Le projet PEAN est un fork du projet MEAN.JS (à ne pas confondre avec MEAN.IO ou la pile generic MEAN).
PEAN remplace MongoDB et Mongoose ORM par PostgreSQL et Sequelize. Le principal avantage du projet MEAN.JS réside dans l'organisation qu'il fournit à une pile comportant de nombreuses pièces en mouvement.
Vous pouvez importer des modèles à partir d'autres fichiers avec sequelize.import
http://sequelizejs.com/documentation#models-import
De cette façon, vous pouvez avoir un module singleton pour sequelize, qui charge ensuite tous les autres modèles.
En fait, cette réponse est assez similaire à la réponse de user1778770.
Vous pouvez également utiliser une injection de dépendance qui fournit une solution élégante à cela. En voici un https://github.com/justmoon/reduct