web-dev-qa-db-ja.com

sequelizeを使用するノードアプリを整理する方法は?

Sequelize ORMを使用するサンプルnodejsアプリを探しています。

私の主な懸念は、require()依存関係ループのためにモデルが相互に複雑な関係を持っている場合、別々のjsファイルでモデルを定義することはほとんど不可能だと思われることです。たぶん、非常に長い1つのファイルですべてのモデルを定義するのでしょうか?

私は主に、モデルがどのように定義され、アプリ全体で使用されるかに興味があります。私は自分でやっていることが物事を行うための「良い」方法であることをいくつか検証したいと思います。

117
mkoryak

短編小説

この場合のトリックは、ファイル内でモデルを初期化することではなく、ファイルの初期化に必要な情報を提供し、集中モジュールがモデルのセットアップとインスタンス化を処理できるようにすることです。

手順は次のとおりです。

  • フィールド、関係、オプションなど、モデルに関するデータを含む複数のモデルファイルがあります。
  • これらのすべてのファイルをロードし、すべてのモデルクラスと関係をセットアップするシングルトンモジュールを用意します。
  • App.jsファイルでシングルトンモジュールをセットアップします。
  • シングルトンモジュールからモデルクラスを取得しますしないモデルファイルでrequireを使用し、代わりにシングルトンからモデルをロードします。

長い話

このソリューションの詳細と対応するソースコードを以下に示します。

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

編集:これは非常に古い答えです! (情報については下を読む)

それは古く、多くの点で制限されています!

  • 最初、@ jinglesthulaがコメントで言及したように(そして私も経験しました)-それらのファイルを要求することには問題があります。 requirereaddirSyncと同じように機能しないためです!

  • Second-あなたはveryリレーションシップに制限-コードはそれらの関連付けにoptionsを提供しないのでbelongsToManyプロパティが必要なため、throughを作成できません。最も基本的な関連付けを作成できます。

  • サード-モデルの関係が非常に制限されています!コードをよく読むと、リレーションはArrayではなくObjectであることがわかります。したがって、複数を作成する場合は、同じタイプの関連付け(belongsToを2回持つなど)-できません!

  • 4番目-シングルトンのことは必要ありません。 nodejsのすべてのモジュールはそれ自体がシングルトンであるため、このすべてのモジュールは理由もなく非常に複雑です。

ファームの答えが表示されます! (記事へのリンクは壊れていますが、sequelizeの公式サンプルで修正します: https://github.com/sequelize/express-example/blob/master/models/index.js -プロジェクト全体を参照して、何が起こっているのかを把握できます。

追伸私はこの投稿を編集しているので、あまりにも支持されているので、人々は新しい答えさえ見ることができません(私がしたように)。

編集:リンクを同じ投稿のコピーに変更しましたが、Githubページにあります

119
user1778770

SequelizeJSには記事があります この問題を解決するWebサイトにあります。

リンクは壊れていますが、動作中のサンプルプロジェクトを見つけることができます こちら を参照してください。上記の編集済みの回答を参照して、これがより良いソリューションである理由を確認してください。

記事から抽出:

  • models/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)
    
92
Farm

パッケージを作成しました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;

これが誰かの助けになることを願っています。

26
Jacob

Express.jsアプリでSequelizeを使い始めました。すぐに、あなたが説明している性質の問題に出くわしました。 Sequelizeをよく理解していなかったのかもしれませんが、1つのテーブルから選択する以上のことをするのはあまり便利ではありませんでした。通常、2つ以上のテーブルから選択するか、純粋なSQLのユニオンを使用する場合は、個別のクエリを実行する必要があり、Nodeの非同期性により、複雑さが増します。

そのため、Sequelizeの使用をやめました。さらに、モデルでDBからフェッチするデータを使用することから切り替えています。私の意見では、データの取得を完全に抽象化する方が良いと考えています。また、理由は-MySQLを使用するだけではないことを想像してください(私の場合、MySQLとMongoDBを並べて使用しています)が、データプロバイダーやトランスポート方法(例: SQL、no-SQL、ファイルシステム、外部API、FTP、SSHなど。モデルですべてを実行しようとすると、最終的にはアップグレードやデバッグが困難な複雑で理解しにくいコードが作成されます。

今、あなたがしたいことは、モデルにデータを取得する場所と方法を知っているレイヤーからデータを取得することですが、モデルはAPIメソッドのみを使用しますfetchsavedeleteなど。このレイヤー内には、特定のデータプロバイダーの特定の実装があります。例えば。ローカルマシン上のPHPファイル、Facebook API、Amazon AWS、またはリモートHTMLドキュメントなどから特定のデータをリクエストできます。

PSこれらのアイデアのいくつかは、ArchitectからCloud9 http://events.yandex.ru/talks/300/

9
mvbl fst

私はそれを農場として設定し、文書で説明しています。

しかし、各関数のモデルにアタッチするインスタンスメソッドとクラスメソッドでは、他のデータベースオブジェクトを取得するためにインデックスファイルが必要になるという追加の問題がありました。

すべてのモデルにアクセスできるようにすることで解決しました。

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

クラスメソッドに対してのみこれを行いましたが、インスタンスメソッドに対しても同じことを行うことができます。

5
jacob

私は公式ガイドに従っています: http://sequelizejs.com/herok 、これにはモデルフォルダがあり、各モジュールを個別のファイルに設定し、それらをインポートして関係を設定するインデックスファイルがありますその中で。

2
Ron

サンプルモデル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;
};

Sequelize ORMを使用するサンプルnodejsアプリを探しています。

PEAN.JSボイラープレートソリューションをご覧ください。

PEAN.JSは、フルスタックのJavaScriptオープンソースソリューションであり、PostgreSQL、Node.js、Express、およびAngularJSベースのアプリケーションの強固な出発点を提供します。

PEANプロジェクトはMEAN.JSプロジェクトの分岐です(MEAN.IOまたはgenericMEANスタックと混同しないでください)。

PEANは、MongoDBとMongoose ORMをPostgreSQLとSequelizeに置き換えます。 MEAN.JSプロジェクトの主な利点は、多くの可動部分を持つスタックに提供される組織です。

1
mg1075

sequelize.importで他のファイルからモデルをインポートできます http://sequelizejs.com/documentation#models-import

そうすれば、sequelize用のシングルトンモジュールを1つ持つことができ、それが他のすべてのモデルをロードします。

実際、この答えはuser1778770の答えと非常に似ています。

1
natrixnatrix89

また、これに対するエレガントなソリューションを提供する依存性注入を使用することもできます。 https://github.com/justmoon/reduct

0