Bagaimana cara mengatur aplikasi simpul yang menggunakan sekuel?

125

Saya mencari contoh aplikasi nodejs yang menggunakan sekuel ORM.

Perhatian utama saya adalah bahwa tampaknya hampir mustahil untuk mendefinisikan model Anda dalam file js terpisah jika model-model tersebut memiliki hubungan yang kompleks satu sama lain karena memerlukan () loop ketergantungan. Mungkin orang mendefinisikan semua model mereka dalam satu file yang sangat panjang?

Saya terutama tertarik pada bagaimana model didefinisikan dan digunakan di seluruh aplikasi. Saya ingin memiliki beberapa validasi bahwa apa yang saya lakukan sendiri adalah cara "baik" untuk melakukan sesuatu.

mkoryak
sumber
2
Saya menambahkan contoh yang mungkin akan membantu seseorang github.com/shaishab/ berikutnyaelize
express
Saya telah menulis sebuah artikel tentang solusi kami: medium.com/@ismayilkhayredinov/...
hypeJunction

Jawaban:

125

Cerpen

Trik dalam hal ini adalah tidak untuk menginisialisasi model di file tetapi hanya untuk memberikan informasi yang diperlukan untuk inisialisasi dan membiarkan modul terpusat mengurus pengaturan model dan instantiasi.

Jadi langkah-langkahnya adalah:

  • Memiliki beberapa file Model dengan data tentang model, seperti bidang, hubungan, dan opsi.
  • Memiliki modul singleton yang memuat semua file tersebut dan mengatur semua kelas model dan hubungan.
  • Siapkan modul singleton Anda di file app.js.
  • Dapatkan kelas model dari modul singleton tidak digunakan requirepada file model Anda, muat model dari singleton saja.

Cerita yang lebih panjang

Berikut adalah deskripsi yang lebih rinci tentang solusi ini dengan kode sumber yang sesuai:

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

EDIT: Ini adalah jawaban yang sangat lama! (baca untuk info)

Tua dan terbatas dalam banyak hal!

  • Pertama , seperti @jinglesthula disebutkan dalam komentar (dan saya mengalaminya juga) - ada masalah dengan memerlukan file-file itu. Itu karena requiretidak bekerja dengan cara yang sama readdirSync!

  • Kedua - hubungan Anda sangat terbatas - kode tidak memberikan opsi untuk asosiasi tersebut sehingga Anda TIDAK BISA membuat belongsToManykarena membutuhkan throughproperti. Anda dapat membuat assocs paling dasar.

  • Ketiga - Anda sangat terbatas dalam hubungan model! Jika Anda membaca kode dengan cermat, Anda akan melihat bahwa relasi adalah sebuah objek, bukan sebuah Array , jadi jika Anda ingin membuat lebih dari satu asosiasi dengan tipe yang sama (seperti memiliki dua kali belongsTo) - Anda tidak bisa!

  • Keempat - Anda tidak perlu benda tunggal itu. Setiap modul di nodejs adalah singleton dengan sendirinya, jadi semua ini membuat cukup kompleks tanpa alasan.

Anda harus melihat jawaban Farm! (Tautan ke artikel rusak, tetapi saya akan memperbaikinya dengan sampel resmi ini dari sekuel: https://github.com/ followingelize/express-example/blob/master/models/index.js - Anda dapat menelusuri seluruh proyek untuk mendapatkan ide tentang apa yang terjadi).

ps saya mengedit posting ini karena sangat tervvotikasi sehingga orang bahkan tidak akan melihat jawaban baru (seperti yang saya lakukan).

Sunting: Baru saja mengubah tautan ke salinan dari pos yang sama, tetapi di Halaman Github

pengguna1778770
sumber
Juga, saya berada di bawah kesan bahwa semua requiremodul d di node dalam arti tunggal karena kode di dalamnya dieksekusi sekali dan kemudian di-cache, sehingga lain kali Anda membutuhkannya Anda mendapatkan referensi objek yang di-cache. Bukankah ini gambaran keseluruhannya?
mkoryak
1
@mkoryak, Anda benar - semua modul commonjs di node secara efektif lajang, karena nilai yang dikembalikan di-cache setelah eksekusi pertama. nodejs.org/api/modules.html#modules_caching
Casey Flynn
2
Jadi, contohnya dapat disederhanakan dengan menghapus bagian rumit tunggal dan hanya menempatkan module.exports = new OrmClass (). Saya akan mencobanya, terima kasih atas tanggapan Anda :)
user1778770
2
Kalau-kalau ada yang sakit kepala, saya akan menyelamatkan Anda. Saya memiliki masalah dengan kode yang tercantum dalam artikel github yang berpusat di sekitar jalur. Saya harus menambahkan. untuk yang membutuhkan (seperti ini: var object = require ('.' + modelsPath + "/" + name);) dan juga mengembalikan jika name.indexOf ('DS_Store')> -1 di forEach dalam fungsi init (yay OSX). Semoga itu bisa membantu.
jinglesthula
seperti yang disebutkan oleh @jinglesthula - ada beberapa perubahan / bug dalam sampel untuk memuat file dalam direktori yang bersembunyi (terutama jika bersarang di tempat lain). Saya juga akan menambahkan kemampuan untuk meneruskan opsi ke hubungan, karena mereka sangat penting (seperti nama kunci asing, jika itu dibiarkan nol, dll.)
Andrey Popov
96

SequelizeJS memiliki artikel di situs web mereka yang memecahkan masalah ini.

Tautan rusak, tetapi Anda dapat menemukan proyek sampel yang berfungsi di sini dan menjelajahinya. Lihat jawaban yang diedit di atas untuk melihat mengapa ini adalah solusi yang lebih baik.

Ambil dari artikel:

  • models / index.js

    Gagasan dari file ini adalah untuk mengkonfigurasi koneksi ke database dan untuk mengumpulkan semua definisi Model. Setelah semuanya ada, kami akan memanggil metode yang terkait pada masing-masing Model. Metode ini dapat digunakan untuk mengaitkan Model dengan orang lain.

          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)
Tanah pertanian
sumber
12
Ini adalah cara Sequelize merekomendasikan untuk melakukannya. Saya akan menerima ini sebagai jawaban yang benar.
jpotts18
3
Ini bagus, tetapi Anda tidak dapat menggunakan model dari metode contoh model lain, atau mungkin saya melewatkan sesuatu.
mlkmt
1
Halaman itu tidak ada lagi
Mike Cheel
1
Inilah tautan yang berfungsi: sequelize.readthedocs.org/en/1.7.0/articles/express
chrisg86
3
@mlkmt Anda bisa! Karena Anda memiliki akses ke sequelizevariabel dalam file model Anda, Anda dapat mengakses model lain dengan sequelize.models.modelName.
Guilherme Sehn
29

Saya telah membuat paket sequelize-connect untuk membantu orang menangani masalah ini. Ini mengikuti konvensi Sequelize disarankan di sini: http://sequelize.readthedocs.org/en/1.7.0/articles/express/

Selain itu ia juga berfungsi sedikit lebih mirip Mongoose dalam hal antarmuka. Ini memungkinkan Anda untuk menentukan serangkaian lokasi di mana model Anda berada dan juga memungkinkan Anda untuk menentukan fungsi pencocokan khusus untuk mencocokkan file model Anda.

Penggunaannya pada dasarnya seperti ini:

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

Kemudian Anda dapat mengakses model dan sekuel seperti:

var orm       = require('sequelize-connect');
var sequelize = orm.sequelize;
var Sequelize = orm.Sequelize;
var models    = orm.models;
var User      = models.User;

Semoga ini bisa membantu seseorang.

jspizziri
sumber
3
Menautkan ke artikel sedikit membantu. Mengutip beberapa dokumen lebih baik. Menampilkan cuplikan kode sangat bagus .... Tetapi sebenarnya membangun perpustakaan yang memecahkan masalah dan menaruhnya di NPM sangat fantastis dan pantas mendapatkan lebih banyak cinta! +1 dan akan membintangi proyek Anda.
Stijn de Witt
9

Saya mulai menggunakan Sequelize di aplikasi Express.js. Tak lama kemudian, muncul masalah sifat yang Anda gambarkan. Mungkin aku tidak begitu mengerti Sequelize, tetapi bagiku melakukan banyak hal lebih dari sekadar memilih dari satu meja tidak terlalu nyaman. Dan di mana biasanya Anda akan menggunakan pilih dari dua tabel atau lebih, atau penyatuan dalam SQL murni, Anda harus menjalankan pertanyaan terpisah, dan dengan sifat async dari Node itu hanya menambah kompleksitas.

Karena itu saya pindah dari menggunakan Sequelize. Selain itu saya beralih dari menggunakan data APA SAJA mengambil dari DB dalam model. Menurut pendapat saya lebih baik abstrak untuk mendapatkan data sepenuhnya. Dan alasannya - bayangkan Anda tidak hanya menggunakan MySQL (dalam kasus saya, saya menggunakan MySQL dan MongoDB berdampingan), tetapi Anda bisa mendapatkan data dari penyedia data apa pun dan metode transportasi apa pun, misalnya SQL, no-SQL, sistem file, API eksternal, FTP, SSH dll. Jika Anda mencoba melakukan semua itu dalam model, Anda akhirnya akan membuat kode yang rumit dan sulit dipahami yang akan sulit untuk ditingkatkan dan didebug.

Sekarang apa yang ingin Anda lakukan adalah untuk memiliki model mendapatkan data dari lapisan yang tahu di mana dan bagaimana untuk mendapatkannya, tapi model Anda hanya menggunakan metode API, misalnya fetch, save,delete dll Dan di dalam lapisan ini Anda memiliki implementasi spesifik untuk penyedia data tertentu. Misalnya, Anda dapat meminta data tertentu dari file PHP di komputer lokal atau dari Facebook API atau dari Amazon AWS atau dari dokumen HTML jarak jauh, dll.

PS beberapa ide ini dipinjam dari Architect oleh Cloud9 : http://events.yandex.ru/talks/300/

mvbl fst
sumber
Ini adalah poin yang valid, tapi aku lebih suka menghindari reimplementing fetch, save, deletedll di luar Sequelizemengingat bahwa kerangka sudah menyediakan sarana. Itu lebih bagus, tetapi kurang nyaman untuk memiliki lapisan pengambilan yang terpisah. Pada saat yang sama, Anda mungkin bisa menambahkan lapisan abstraksi mengambil sekitar Sequelize tetapi kemudian solusinya lebih rumit, untuk kemenangan yang bisa diperdebatkan.
Zorayr
tutorial ini sangat membantu: sekuel + contoh express
Lucas Do Amaral
@ mvbl-fst Anda baru saja menggambarkan layer DAO. Katakanlah Anda memiliki beberapa pengguna dalam SQL DB dan pengguna yang berbeda di sistem file. Anda harus memiliki dua DAO yang abstrak cara mendapatkan masing-masing, kemudian lapisan bisnis yang menyatukan pengguna (mungkin bahkan menyesuaikan beberapa properti) dan meneruskannya kembali ke rute Anda (lapisan presentasi).
DJDaveMark
5

Saya mengaturnya seperti yang dijelaskan Farm dan dokumentasi.

Tapi saya mengalami masalah tambahan bahwa dalam metode instance saya dan metode kelas yang akan saya lampirkan ke model di setiap fungsi saya akan memerlukan file indeks untuk mendapatkan objek database lainnya.

Memecahkannya dengan membuatnya dapat diakses oleh semua model.

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

Dan dalam file model

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

Saya hanya melakukan ini untuk metode kelas tetapi Anda juga bisa melakukan hal yang sama misalnya metode.

Jacobs
sumber
+1 untuk prototipe classMethod yang mengembalikan db. Tepatnya ide yang saya cari untuk dapat memuat classMethods selama define tetapi juga dapat merujuk setiap Model dalam ClassMethod (yaitu untuk menyertakan hubungan)
bitwit
2

Saya mengikuti panduan resmi: http://afterelizejs.com/heroku , yang memiliki folder model, mengatur setiap modul dalam file terpisah, dan memiliki file indeks untuk mengimpornya dan mengatur hubungan di antara mereka.

Ron
sumber
tautan tidak valid
prisar
2

Contoh model melakukan sekuel

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


Muhammad Arief Trimanda
sumber
1

Anda dapat mengimpor model dari file lain dengan sequelize.import http://afterelizejs.com/documentation#models-import

Dengan begitu Anda dapat memiliki satu modul tunggal untuk sekuel, yang kemudian memuat semua model lainnya.

Sebenarnya jawaban ini sangat mirip dengan jawaban user1778770.

natrixnatrix89
sumber
1
apakah ini bekerja dengan dependensi melingkar? Misalnya ketika model A memiliki FK untuk model B dan model menjadi memiliki FK untuk model A
mkoryak
1

Saya mencari contoh aplikasi nodejs yang menggunakan sekuel ORM.

Anda mungkin tertarik untuk melihat solusi boilerplate PEAN.JS.

PEAN.JS adalah solusi open-source JavaScript stack penuh, yang menyediakan titik awal yang solid untuk PostgreSQL, Node.js, Express, dan aplikasi berbasis AngularJS.

Proyek PEAN adalah cabang dari proyek MEAN.JS (jangan dikelirukan dengan MEAN.IO atau tumpukan MEAN generik ).

PEAN menggantikan MongoDB dan Mongoose ORM dengan PostgreSQL dan Sequelize. Manfaat utama dari proyek MEAN.JS adalah organisasi yang disediakannya untuk tumpukan yang memiliki banyak bagian bergerak.

mg1075
sumber
0

Anda juga dapat menggunakan suntikan ketergantungan yang memberikan solusi elegan untuk ini. Ini satu https://github.com/justmoon/reduct

Vahe Hovhannisyan
sumber