Как организовать приложение node, использующее sequelize?

Я ищу пример nodejs-приложения, в котором используется синтаксический ORM.

Моя главная проблема заключается в том, что кажется, что невозможно определить ваши модели в отдельных файлах js, если эти модели имеют сложные отношения друг с другом из-за require() циклов зависимостей. Может быть, люди определяют все свои модели в одном файле, который очень длинный?

Меня в основном интересуют, как модели определяются и используются через приложение. Я хотел бы получить некоторую проверку того, что то, что я делаю самостоятельно, - это "хороший" способ сделать что-то.

Ответ 1

Рассказ

В этом случае фокусом является не инициализация модели в файле, а просто предоставление необходимой информации для ее инициализации, и пусть централизованный модуль позаботится о настройке и создании моделей.

Итак, шаги:

  • Имеет несколько файлов модели с данными о модели, например поля, отношения и параметры.
  • Имейте модуль singleton, который загружает все эти файлы и настраивает все классы моделей и отношения.
  • Настройте модуль singleton в файле app.js.
  • Получить классы моделей из модуля singleton не использовать require в ваших файлах моделей, загрузите модели из сингла. Вместо этого

Более длинная история

Вот более подробное описание этого решения с соответствующим исходным кодом:

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

EDIT: Это очень старый ответ! (читать для информации)

Это старый и ограниченный во многих отношениях!

  • Первый, как @jinglesthula, упомянутый в комментариях (и я тоже это испытал) - есть проблемы с требованием этих файлов. Это потому, что require работает не так, как readdirSync!

  • Второй - вы очень ограничены в отношениях - код не предоставляет параметры для этих ассоциаций, поэтому вы UNABLE для создания belongsToMany, поскольку для этого требуется свойство through. Вы можете сделать самые основные ассоциации.

  • Третий - вы очень ограничены в модельных отношениях! Если вы внимательно прочитаете код, вы увидите, что отношения Объект вместо Массив, поэтому, если вы хотите сделать более одного ассоциации одного типа (например, имеющие два раза belongsTo) - вы не можете!

  • Четвертый. Вам не нужен этот синглтон. Каждый модуль в nodejs сам по себе является одиночным, поэтому все это делает довольно сложным без каких-либо причин.

Вы должны увидеть ответ Фермы! (Ссылка на статью нарушена, но я исправлю ее с помощью этого официального примера из sequelize: https://github.com/sequelize/express-example/blob/master/models/index.js - вы можете просмотреть весь проект, чтобы получить представление о том, что происходит).

p.s. Я редактирую этот пост, так как он настолько популярен, что люди даже не видят никаких новых ответов (как и я).

Изменить: Просто изменил ссылку на копию того же сообщения, но на странице Github

Ответ 2

На этом веб-сайте SequelizeJS есть статья, которая решает эту проблему.

Ссылка сломана, но вы можете найти рабочий образец проекта здесь и просмотреть его. См. Отредактированный ответ выше, чтобы понять, почему это лучшее решение.

Извлечение из статьи:

  • Модели/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)
    

Ответ 3

Я создал пакет 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;

Надеюсь, это поможет кому-то.

Ответ 4

Я начал использовать Sequelize в приложении Express.js. Достаточно скоро столкнулись с проблемами характера, который вы описываете. Может быть, я не совсем понял Sequelize, но для меня это делало больше, чем просто выбор из одного стола, было не очень удобно. И там, где обычно вы можете выбирать из двух или более таблиц или объединяться в чистый SQL, вам придется запускать отдельные запросы, а с асинхронным характером Node это просто добавило сложности.

Поэтому я отошел от использования Sequelize. Более того, я перехожу от использования ЛЮБОЙ выборки данных из БД в моделях. На мой взгляд, лучше абстрагироваться от получения данных полностью. И причины - представьте, что вы не просто используете MySQL (в моем случае я использую MySQL и MongoDB бок о бок), но вы можете получать свои данные от любого поставщика данных и любого транспортного метода, например. SQL, no-SQL, файловая система, внешний API, FTP, SSH и т.д. Если вы попытаетесь сделать все это в моделях, вы в конечном итоге создадите сложный и понятный код, который будет сложно обновить и отладить.

Теперь то, что вы хотите сделать, это заставить модели получать данные со слоя, который знает, где и как его получить, но ваши модели используют только методы API, например. fetch, save, delete и т.д. И внутри этого слоя у вас есть конкретные реализации для конкретных поставщиков данных. Например. вы можете запросить определенные данные из файла PHP на локальном компьютере или из Facebook API или из Amazon AWS или из удаленного документа HTML и т.д.

PS некоторые из этих идей были заимствованы у архитектора Cloud9: http://events.yandex.ru/talks/300/

Ответ 5

Я установил его как ферму и описал документацию.

Но у меня была дополнительная проблема в том, что в моих методах экземпляра и методах класса, которые я буду прикреплять к моделям в каждой функции, мне нужно будет потребовать, чтобы файл индекса захватил другие объекты базы данных.

Решила его, сделав их доступными для всех моделей.

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

Я сделал это только для методов класса, но вы также можете сделать то же самое, например, методы.

Ответ 6

Я следую официальному руководству: http://sequelizejs.com/heroku, в котором есть папка с образцами, каждый модуль создается в отдельных файлах и имеет индексный файл, чтобы импортировать их и установить взаимосвязь между ними.

Ответ 7

Вы можете импортировать модели из других файлов с помощью sequelize.import http://sequelizejs.com/documentation#models-import

Таким образом, вы можете использовать один сингл-модуль для продолжения, который затем загружает все остальные модели.

На самом деле этот ответ очень похож на ответ пользователя1778770.

Ответ 8

Я ищу пример nodejs-приложения, в котором используется синтаксический ORM.

Вам может быть интересно посмотреть на решение панели PEAN.JS.

PEAN.JS - это полнотекстовое JavaScript-решение с открытым исходным кодом, которое обеспечивает прочную отправную точку для приложений PostgreSQL, Node.js, Express и AngularJS.

Проект PEAN является вилкой проекта MEAN.JS(не следует путать с MEAN.IO или общим стеком MEAN).

PEAN заменяет MongoDB и Mongoose ORM PostgreSQL и Sequelize. Основным преимуществом проекта MEAN.JS является организация, которую он предоставляет стеку с множеством движущихся частей.

Ответ 9

Вы также можете использовать инъекцию зависимостей, которая обеспечивает элегантное решение. Здесь один https://github.com/justmoon/reduct