[node.js] sequelize를 사용하는 노드 앱을 구성하는 방법은 무엇입니까?

sequelize ORM을 사용하는 예제 nodejs 앱을 찾고 있습니다.

내 주요 관심사는 require () 종속성 루프로 인해 모델이 서로 복잡한 관계를 갖는 경우 별도의 js 파일에서 모델을 정의하는 것이 거의 불가능 해 보인다는 것입니다. 사람들은 매우 긴 하나의 파일에 모든 모델을 정의 할 수 있습니까?

저는 주로 앱을 통해 모델을 정의하고 사용하는 방법에 관심이 있습니다. 내가 혼자하는 일이 일을하는 “좋은”방법이라는 것을 확인하고 싶습니다.



답변

짧은 이야기

이 경우 트릭은 모델을 초기화하지 않는 것 입니다. 파일하지만 단지 초기화에 대한 모든 necesary 정보를 제공하고 모델 설정 및 인스턴스의 중앙 모듈 돌봐를 할 수 있습니다.

따라서 단계는 다음과 같습니다.

  • 필드, 관계 및 옵션과 같은 모델에 대한 데이터가있는 여러 모델 파일이 있습니다.
  • 모든 파일을로드하고 모든 모델 클래스와 관계를 설정하는 싱글 톤 모듈이 있습니다.
  • app.js 파일에서 싱글 톤 모듈을 설정하십시오.
  • 모델 파일에서 사용 하지 않는 싱글 톤 모듈에서 모델 클래스를 가져 require오고 대신 싱글 톤에서 모델을로드하십시오.

더 긴 이야기

다음은 해당 소스 코드와 함께이 솔루션에 대한 자세한 설명입니다.

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

편집 : 이것은 아주 오래된 대답입니다! (정보를 위해 아래를 읽으십시오)

오래되고 여러면에서 제한적입니다!

  • 첫째 , @jinglesthula가 주석에서 언급했듯이 (그리고 저도 경험했습니다)-해당 파일을 요구하는 데 문제가 있습니다. require와 같은 방식으로 작동하지 않기 때문입니다 readdirSync!

  • 둘째 – 당신이하는 매우 관계 제한 – 코드는 제공하지 않습니다 옵션 은 그래서 그 단체에을 수 없음 만들 belongsToMany그것을 필요로 through속성을. 가장 기본적인 assocs를 만들 수 있습니다.

  • 셋째 -모델 관계가 매우 제한적입니다! 코드를 자세히 읽으면 관계가 Array 대신 객체 라는 것을 알 수 있으므로 동일한 유형의 연관을 두 개 이상 만들고 싶다면 (예 : 두 번 사용 ) 불가능합니다!belongsTo

  • 넷째 -당신은 그 싱글 톤이 필요하지 않습니다. nodejs의 모든 모듈은 그 자체로 싱글 톤이므로이 모든 것이 이유없이 매우 복잡합니다.

농장의 대답이 보여야합니다! (기사에 대한 링크가 깨졌지만 속편의 공식 샘플을 사용하여 수정하겠습니다. https://github.com/sequelize/express-example/blob/master/models/index.js – 당신은 목록을 검색 할 수 있습니다 무슨 일이 일어나고 있는지에 대한 아이디어를 얻기 위해 전체 프로젝트).

추신 나는 사람들이 (내가 한 것처럼) 새로운 답변을 볼 수 없을 정도로 너무 upvoted 때문에이 게시물을 편집하고 있습니다.

편집 : 링크를 동일한 게시물의 사본으로 변경했지만 Github 페이지에서


답변

SequelizeJS는 웹 사이트에이 문제를 해결 하는 기사가지고 있습니다.

링크가 끊어졌지만 여기서 작동하는 샘플 프로젝트 를 찾아서 찾아 볼 수 있습니다. 이것이 더 나은 솔루션 인 이유를 보려면 위의 편집 된 답변을 참조하십시오.

기사에서 추출 :

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

답변

사람들이이 문제를 처리 할 수 ​​있도록 패키지 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;

바라건대 이것은 누군가를 도울 것입니다.


답변

Express.js 앱에서 Sequelize를 사용하기 시작했습니다. 곧 당신이 묘사하는 성격의 문제에 부딪 혔습니다. Sequelize를 잘 이해하지 못했을 수도 있지만 한 테이블에서 선택하는 것 이상의 일을하는 것이 정말 편리하지 않았습니다. 그리고 일반적으로 둘 이상의 테이블에서 선택하거나 순수 SQL의 통합을 사용하는 경우 별도의 쿼리를 실행해야하며 노드의 비동기 특성으로 인해 복잡성이 추가되었습니다.

따라서 나는 Sequelize 사용에서 멀어졌습니다. 또한 모델의 DB에서 가져 오는 모든 데이터 사용에서 전환하고 있습니다. 제 생각에는 데이터를 완전히 추상화하는 것이 좋습니다. 그리고 그 이유는-여러분이 MySQL을 사용하는 것이 아니라 (제 경우에는 MySQL과 MongoDB를 나란히 사용합니다), 모든 데이터 공급자와 모든 전송 방법 (예 : SQL, no-SQL)에서 데이터를 가져올 수 있다고 상상해보십시오. 파일 시스템, 외부 API, FTP, SSH 등. 모델에서 모든 작업을 수행하려고하면 결국 업그레이드 및 디버그가 어려운 복잡하고 이해하기 어려운 코드가 생성됩니다.

이제 당신이하고 싶은 모델은 어디서 어떻게 그걸 얻기 위해 알고있는 계층에서 데이터를 얻을 것입니다,하지만 모델의 경우 만 예를 들어, API 방법, 사용 fetch, save, delete등 그리고이 층 내부에 특정 데이터 공급자에 대한 구체적인 구현을 가지고있다. 예를 들어 로컬 머신의 PHP 파일, Facebook API, Amazon AWS 또는 원격 HTML 문서 등에서 특정 데이터를 요청할 수 있습니다.

PS 이러한 아이디어 중 일부는 Cloud9의 Architect 에서 차용 한 것입니다 . http://events.yandex.ru/talks/300/


답변

나는 그것을 Farm으로 설정하고 문서에 설명되어 있습니다.

그러나 각 함수의 모델에 연결할 인스턴스 메서드와 클래스 메서드에서 다른 데이터베이스 개체를 가져 오기 위해 인덱스 파일이 필요하다는 추가 문제가있었습니다.

모든 모델에 액세스 할 수 있도록하여 문제를 해결했습니다.

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

클래스 메서드에 대해서만이 작업을 수행했지만 인스턴스 메서드에 대해서도 동일한 작업을 수행 할 수 있습니다.


답변

나는 공식 가이드를 따르고있다 : http://sequelizejs.com/heroku , 모델 폴더가 있고 각 모듈을 별도의 파일로 설정하고 인덱스 파일을 가져 와서 이들 간의 관계를 설정합니다.


답변

샘플 모델 속편

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