Comment organiser une application de noeud qui utilise sequelize?

Je cherche un exemple d'application nodejs qui utilise l'ORM sequelize.

Ma principale préoccupation est qu'il semble presque impossible de définir vos modèles dans des fichiers JS séparés si ces modèles ont des relations complexes les uns avec les autres en raison de boucles de dépendance require (). Peut-être que les gens définissent tous leurs modèles dans un fichier très très long?

Je suis principalement intéressé par la façon dont les modèles sont définis et utilisés à travers l'application. Je voudrais avoir une certaine validation que ce que je suis sur mon propre est la "bonne" façon de faire les choses.

107
demandé sur mkoryak 2012-09-19 05:33:22

10 réponses

La Nouvelle

L'astuce dans ce cas n'est pas d'initialiser le modèle dans le fichier mais simplement de fournir les informations nécessaires à son initialisation et de laisser un module centralisé s'occuper de la configuration et de l'instanciation des modèles.

Donc les étapes sont:

  • ont plusieurs fichiers de modèle avec des données sur le modèle, comme les champs, les relations et les options.
  • avoir un module singleton qui charge tous ces fichiers et configure toutes les classes de modèle et relation.
  • configurez votre module singleton sur l'application.fichier js.
  • récupère les classes de modèle à partir du module singleton ne pas utiliser require sur vos fichiers de modèle, charger les modèles à partir du singleton à la place.

La plus longue histoire

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

EDIT: c'est un très vieux réponse! (lire pour info)

Il est vieux et limité à bien des égards!

  • Tout d'abord , comme @ jingleshula mentionné dans les commentaires ( et je l'ai expérimenté aussi) - il y a des problèmes avec l'exigence de ces fichiers. C'est parce que require ne fonctionne pas de la même manière que readdirSync!

  • Deuxième - vous très limité dans les relations - le code ne fournit pas de options ces associations afin de vous INCAPABLE pour créez belongsToMany comme il a besoin de la propriété through. Vous pouvez faire les assocs les plus élémentaires.

  • Troisièmement - Vous êtes très limité dans les relations modèles! Si vous lisez attentivement le code, vous verrez que les relations est un Object au lieu de Matrice, donc si vous voulez faire de plus d'un associations du même type (comme d'avoir deux fois belongsTo) - vous ne pouvez pas!

  • Quatrième - Vous n'avez pas besoin que singleton truc. Chaque module dans nodejs est singleton par lui-même, donc tout cela fait est assez 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 post car il est tellement upvoted que les gens ne verront même pas de nouvelles réponses (comme je faire).

Edit: {[23] } vient de changer le lien vers une copie du même message, mais dans une Page Github

112
répondu user1778770 2016-02-01 00:32:41

SequelizeJS a un article sur leur site web qui résout ce problème.

le lien est cassé, mais vous pouvez trouver l'exemple de projet ici et le parcourir. Voir édité réponse ci-dessus pour voir pourquoi c'est 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 le méthode associée sur 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)
    
89
répondu Farm 2015-12-04 06:23:35

J'ai créé un paquet sequelize-connect pour aider les gens à faire face à ce problème. Il suit la convention suggérée par Sequelize ici: http://sequelize.readthedocs.org/en/1.7.0/articles/express/

De plus, il fonctionne aussi un peu plus comme Mangouste 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 pour correspondre à votre modèle fichier.

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 sequelize comme ceci:

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.

24
répondu Jacob 2016-04-19 13:47:45

J'ai commencé à utiliser Sequelize dans Express.js app. Assez vite rencontré des problèmes de la nature que vous décrivez. Peut-être que je ne comprenais pas tout à fait Sequelize, mais pour moi faire des choses plus que de simplement sélectionner à partir d'une table n'était pas vraiment pratique. Et où normalement vous utiliseriez select from deux tables ou plus, ou une union en SQL pur, vous devrez exécuter des requêtes séparées, et avec la nature asynchrone du nœud, il suffit d'ajouter de la complexité.

Par conséquent, je me suis éloigné de L'utilisation de Sequelize. De plus, je passe de l'utilisation de toute récupération de données à partir de DB dans les modèles. À mon avis, il est préférable d'abstraire complètement les données. Et les raisons sont - imaginez que vous n'utilisez pas seulement MySQL (dans mon cas, J'utilise MySQL et MongoDB côte à côte), mais vous pouvez obtenir vos données de n'importe quel fournisseur de données et n'importe quelle méthode de transport, par exemple SQL, no-SQL, système de fichiers, API externe, FTP, SSH etc. Si vous essayiez de tout faire dans les modèles, vous finiriez par créer un code complexe et difficile à comprendre serait difficile à mettre à niveau et à déboguer.

Maintenant, ce que vous voulez faire, c'est que les modèles obtiennent des données à partir d'une couche qui sait où et comment les obtenir, mais vos modèles n'utilisent que 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 ou D'Amazon AWS ou d'un document HTML distant, etc.

PS certaines de ces idées ont été emprunté à partir de Architecte par Cloud9: http://events.yandex.ru/talks/300/

8
répondu mvbl fst 2012-10-31 04:05:29

Je l'ai mis en place comme ferme et la documentation décrit.

Mais j'avais le problème additonal que dans mes méthodes d'instance et les méthodes de classe que j'attacherais aux modèles dans chaque fonction, je devrais exiger que le fichier d'index mette la main sur 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 ne l'ai fait que pour les méthodes de classe mais vous pouvez aussi faire la même chose par exemple méthode.

4
répondu jacob 2014-05-29 19:43:39

Je suis le guide officiel: http://sequelizejs.com/heroku , qui a un dossier models, configure chaque module dans des fichiers séparés, et dispose d'un fichier d'index pour les importer et définir la relation entre eux.

2
répondu Ron 2013-08-06 10:12:23

, 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.

1
répondu natrixnatrix89 2013-06-13 08:32:08

Je suis à la recherche d'un exemple d'application nodejs qui utilise l'ORM sequelize.

Vous pourriez être intéressé à regarder le PEAN.Js solution passe-partout.

PEAN.JS est une solution open-source JavaScript à pile complète, qui fournit un point de départ solide pour PostgreSQL, Node.applications basées sur js, Express et AngularJS.

Le projet PEAN est une fourchette de la moyenne.Projet JS (Non à confondre avec MEAN.IO ou la pile moyenneGénérique ).

PEAN remplace MongoDB et L'ORM Mongoose par PostgreSQL et Sequelize. Un avantage principal de la moyenne.Js project est l'organisation qu'il fournit à une pile qui a beaucoup de pièces mobiles.

1
répondu mg1075 2016-03-23 03:54:26

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

1
répondu Muhammad Arief Trimanda 2018-01-31 17:08:47

Vous pouvez également utiliser une injection de dépendance qui fournit une solution élégante à cela. Voici un https://github.com/justmoon/reduct

0
répondu Vahe Hovhannisyan 2016-10-12 23:57:15