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


125

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

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

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


2
나는 누군가의 도움이 될 수있는 예를 들어 추가 github.com/shaishab/sequelize-express-example을
Shaishab 로이

나는 우리의 솔루션에 대한 기사 작성했습니다 : medium.com/@ismayilkhayredinov/...을
hypeJunction

답변:


125

짧은 이야기

이 경우 트릭은 모델을 초기화하지 않는 것 입니다. 파일하지만 단지 초기화에 대한 모든 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 페이지에서


또한 require노드의 모든 d 모듈이 한 번 실행 된 다음 캐시되기 때문에 노드의 모든 d 모듈이 단일 항목이라는 인상을 받았습니다 . 따라서 다음에 필요할 때 캐시 된 개체 참조를 얻게됩니다. 이것은 전체 그림이 아닙니까?
mkoryak

1
@mkoryak, 당신 말이 맞습니다-반환 된 값이 첫 번째 실행 후 캐시되기 때문에 노드의 모든 commonjs 모듈은 사실상 싱글 톤입니다. nodejs.org/api/modules.html#modules_caching
Casey Flynn

2
따라서 복잡한 싱글 톤 부분을 제거하고 module.exports = new OrmClass () 만 넣어서 예제를 단순화 할 수 있습니다. 나는 당신의 의견, 감사합니다 :) 그것을 밖으로 시도 할 것이다
user1778770

2
누군가가 내가 두통을 앓을 경우에 대비해 내가 당신을 구할 것입니다. 경로 중심의 github 기사에 나열된 코드에 문제가 있습니다. 나는. 요구에 (예 : var object = require ( '.'+ modelsPath + "/"+ name);) 그리고 init 함수의 forEach에 name.indexOf ( 'DS_Store')> -1이면 리턴을 넣으십시오. (예 OSX). 도움이되기를 바랍니다.
jinglesthula 2013

@jinglesthula가 언급했듯이-샘플에 디렉터리를 사용하여 파일을로드하기위한 몇 가지 변경 / 버그가 있습니다 (특히 다른 곳에 중첩 된 경우). 또한 관계에 옵션을 전달하는 기능을 추가 할 것입니다. 이는 매우 중요하기 때문입니다 (예 : 외래 키의 이름, null이 허용되는 경우 등).
Andrey Popov

96

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)

12
이것이 Sequelize가 권장하는 방식입니다. 나는 이것을 정답으로 받아 들일 것입니다.
jpotts18

3
이것은 좋지만 다른 모델의 인스턴스 메소드에서 모델을 사용할 수 없거나 아마도 내가 놓친 것이 있습니다.
mlkmt

1
페이지가 더 이상 존재하지 않습니다
마이크 Cheel에게

1
작업 링크는 다음과 같습니다. sequelize.readthedocs.org/en/1.7.0/articles/express
chrisg86

3
@mlkmt 수 있습니다! sequelize모델 파일 의 변수에 액세스 할 수 있으므로 sequelize.models.modelName.
Guilherme Sehn

29

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

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


3
기사에 연결하면 도움이됩니다. 일부 문서를 인용하는 것이 좋습니다. 코드 스 니펫을 보여주는 것은 훌륭합니다 .... 그러나 실제로 문제를 해결하는 라이브러리를 구축하고 NPM에 올리는 것은 환상 적이고 더 많은 사랑을받을 만합니다! +1하고 프로젝트에 별표를 표시합니다.
Stijn de Witt

9

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/


다음은 유효한 점,하지만 난 오히려 재 구현 피할 것 fetch, save, delete의 등 외부 Sequelize프레임 워크가 이미있는 수단을 제공하는 제공합니다. 별도의 페칭 레이어를 갖는 것이 더 좋지만 덜 편리합니다. 동시에 Sequelize 주변에 가져 오는 추상화 계층을 추가 할 수 있지만 그 해결책은 논쟁의 여지가있는 승리를 위해 더 복잡합니다.
Zorayr

이것은 매우 도움이 될 튜토리얼 : sequelize + 예를 표현
루카스 마 아마 랄

@ mvbl-fst 방금 DAO 계층을 설명했습니다. SQL DB에 일부 사용자가 있고 파일 시스템에 다른 사용자가 있다고 가정 해 보겠습니다. 각각을 가져 오는 방법을 추상화하는 두 개의 DAO가 있어야하며, 사용자를 함께 연결 (일부 속성을 조정할 수도 있음)하고 경로 (프레젠테이션 레이어)로 다시 전달하는 비즈니스 계층이 있어야합니다.
DJDaveMark

5

나는 그것을 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
 });
};

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


db를 반환하는 프로토 타입 classMethod에 +1. 정의하는 동안 classMethods를로드 할 수있을뿐만 아니라 ClassMethod (즉, 관계를 포함하기 위해)에있는 모든 모델을 참조 할 수 있기를 원했던 정확히 아이디어
bitwit

2

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


링크가 유효하지 않습니다
prisar 2019-04-12

2

샘플 모델 속편

'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

http://sequelizejs.com/documentation#models-import를 사용 하여 다른 파일에서 모델을 가져올 수 있습니다 sequelize.import .

이렇게하면 sequelize를위한 하나의 싱글 톤 모듈을 사용할 수 있으며 다른 모든 모델을로드 할 수 있습니다.

실제로이 답변은 user1778770의 답변과 매우 유사합니다.


1
순환 종속성과 함께 작동합니까? 예를 들어 모델 A가 B의 모델과 모델이 될 수있는 FK를 가질 때 A를 모델로 FK을 갖는다
mkoryak

1

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

PEAN.JS 상용구 솔루션에 관심이있을 수 있습니다.

PEAN.JS는 PostgreSQL, Node.js, Express 및 AngularJS 기반 애플리케이션을위한 견고한 시작점을 제공하는 풀 스택 JavaScript 오픈 소스 솔루션입니다.

PEAN 프로젝트는 MEAN.JS 프로젝트의 포크입니다 (MEAN.IO 또는 일반 MEAN 스택 과 혼동하지 마십시오 ).

PEAN은 MongoDB 및 Mongoose ORM을 PostgreSQL 및 Sequelize로 대체합니다. MEAN.JS 프로젝트의 주요 이점은 움직이는 부분이 많은 스택에 제공하는 조직입니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.