Làm cách nào để tổ chức một ứng dụng nút sử dụng tuần tự hóa?


125

Tôi đang tìm kiếm một ứng dụng nodejs ví dụ sử dụng ORM tuần tự hóa.

Mối quan tâm chính của tôi là dường như không thể xác định các mô hình của bạn trong các tệp js riêng biệt nếu các mô hình đó có mối quan hệ phức tạp với nhau vì các vòng lặp phụ thuộc request (). Có lẽ mọi người định nghĩa tất cả các mô hình của họ trong một tệp rất dài?

Tôi chủ yếu quan tâm đến cách các mô hình được xác định và sử dụng thông qua ứng dụng. Tôi muốn có một số xác nhận rằng những gì tôi đang làm một mình là cách "tốt" để làm việc.


2
Tôi đã thêm một ví dụ có thể giúp ai đó github.com/shaishab/fterelize-express-example
Shaishab Roy

Tôi đã viết một bài viết về giải pháp của chúng tôi: Medium.com/@ismayilkhayredinov/ Kẻ
hypeJeft

Câu trả lời:


125

Câu chuyện ngắn

Thủ thuật trong trường hợp này không phải là khởi tạo mô hình trong tệp mà chỉ cung cấp thông tin cần thiết cho quá trình khởi tạo của nó và để một mô-đun tập trung đảm nhiệm việc thiết lập và khởi tạo mô hình.

Vì vậy, các bước là:

  • Có một số tệp Mô hình với dữ liệu về mô hình, như các trường, mối quan hệ và tùy chọn.
  • Có một mô-đun singleton tải tất cả các tệp đó và thiết lập tất cả các lớp mô hình và các mối quan hệ.
  • Thiết lập mô-đun singleton của bạn tại tệp app.js.
  • Nhận các lớp mô hình từ mô-đun singleton không sử dụng requiretrên các tệp mô hình của bạn, thay vào đó hãy tải các mô hình từ singleton.

Câu chuyện dài hơn

Dưới đây là mô tả chi tiết hơn về giải pháp này với mã nguồn tương ứng:

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

EDIT: Đây là một câu trả lời rất cũ! (đọc để biết thông tin)

Nó cũ và hạn chế theo nhiều cách!

  • Đầu tiên , như @jinglểula đã đề cập trong các bình luận (và tôi cũng đã trải nghiệm điều đó) - có vấn đề với việc yêu cầu các tệp đó. Đó là bởi vì requirekhông hoạt động theo cùng một cách như readdirSync!

  • Thứ hai - bạn rất hạn chế trong các mối quan hệ - mã không cung cấp tùy chọn cho các liên kết đó để bạn KHÔNG THỂ tạo được belongsToManyvì nó cần throughtài sản. Bạn có thể thực hiện các assocs cơ bản nhất.

  • Thứ ba - bạn rất hạn chế trong quan hệ người mẫu! Nếu bạn đọc kỹ mã, bạn sẽ thấy các mối quan hệ là một đối tượng thay vì một mảng , vì vậy nếu bạn muốn tạo nhiều hơn một liên kết cùng loại (như có hai lần belongsTo) - bạn không thể!

  • Thứ tư - Bạn không cần điều đơn lẻ đó. Mỗi mô-đun trong nodejs đều là singleton, vì vậy tất cả điều này làm cho khá phức tạp mà không có lý do.

Bạn sẽ thấy câu trả lời của Farm! (Liên kết đến bài viết bị hỏng, nhưng tôi sẽ sửa nó bằng mẫu chính thức này từ phần tiếp theo: https://github.com/fterelize/express-example/blob/master/models/index.js - bạn có thể duyệt toàn bộ dự án để có được một ý tưởng về những gì đang xảy ra).

ps Tôi đang chỉnh sửa bài đăng này vì nó được nâng cấp đến mức mọi người thậm chí sẽ không thấy bất kỳ câu trả lời mới nào (như tôi đã làm).

Chỉnh sửa: Chỉ cần thay đổi liên kết thành một bản sao của cùng một bài đăng, nhưng trong Trang Github


Ngoài ra, tôi có ấn tượng rằng tất cả các requiremô-đun d trong nút đều ở dạng singletons vì mã trong chúng được thực thi một lần và sau đó được lưu vào bộ đệm, để lần sau bạn yêu cầu chúng, bạn sẽ nhận được tham chiếu đối tượng được lưu trong bộ nhớ cache. Đây không phải là toàn bộ hình ảnh?
mkoryak

1
@mkoryak, bạn đã đúng - tất cả các mô-đun commonjs trong nút đều là singletons một cách hiệu quả, vì giá trị được trả về được lưu trong bộ đệm sau lần thực hiện đầu tiên. nodejs.org/api/modules.html#modules_caching
Casey Flynn

2
Vì vậy, ví dụ có thể được đơn giản hóa bằng cách loại bỏ phần khó khăn của singleton và chỉ cần đặt module.exports = new OrmClass (). Tôi sẽ dùng thử, cảm ơn phản hồi của bạn :)
user1778770

2
Chỉ trong trường hợp bất cứ ai bị đau đầu, tôi sẽ cứu bạn. Tôi đã có vấn đề với mã được liệt kê trong bài viết github xoay quanh các đường dẫn. Tôi đã phải thêm một. cho các yêu cầu (như thế này: var object = quiries ('.' + modelPath + "/" + name);) và cũng trả về nếu name.indexOf ('DS_Store')> -1 trong forEach trong hàm init (yay OSX). Mong rằng sẽ giúp.
jinglểula

như @jingl salonula đã đề cập - có một số thay đổi / lỗi trong mẫu để tải các tập tin héo thư mục (đặc biệt là nếu nó được lồng ở một nơi khác). Tôi cũng sẽ thêm khả năng chuyển các tùy chọn cho các mối quan hệ, vì chúng rất quan trọng (như tên của khóa ngoại, nếu nó được phép là null, v.v.)
Andrey Popov

96

SequelizeJS có một bài viết trên trang web của họ để giải quyết vấn đề này.

Liên kết bị hỏng, nhưng bạn có thể tìm thấy dự án mẫu làm việc ở đây và duyệt nó. Xem câu trả lời được chỉnh sửa ở trên để xem tại sao đây là một giải pháp tốt hơn.

Trích từ bài viết:

  • mô hình / index.js

    Ý tưởng của tệp này là cấu hình một kết nối đến cơ sở dữ liệu và thu thập tất cả các định nghĩa Mô hình. Khi mọi thứ đã ổn định, chúng tôi sẽ gọi phương thức được liên kết trên mỗi Mô hình. Phương pháp này có thể được sử dụng để liên kết Mô hình với người khác.

          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
Đây là cách mà Sequelize khuyên bạn nên làm điều đó. Tôi sẽ chấp nhận đây là câu trả lời chính xác.
jpotts18

3
Điều này là tốt, nhưng bạn không thể sử dụng một mô hình từ các phương thức cá thể của mô hình khác, hoặc có lẽ tôi đã bỏ lỡ điều gì đó.
mlkmt 30/03/2015

1
Trang này không còn tồn tại nữa
Mike Cheel

1
Đây là liên kết làm việc: sequelize.readthedocs.org/en/1.7.0/articles/express
chrisg86

3
@mlkmt bạn có thể! Vì bạn có quyền truy cập vào sequelizebiến trong tệp mô hình của mình, bạn có thể truy cập mô hình khác với sequelize.models.modelName.
Guilherme Sehn

29

Tôi đã tạo một gói kết nối nối tiếp để giúp mọi người giải quyết vấn đề này. Nó tuân theo quy ước được đề xuất Sequelize tại đây: http : // resultelize.readthedocs.org/en/1.7.0/articles/express/

Ngoài ra, nó cũng có chức năng giống Mongoose hơn một chút về giao diện. Nó cho phép bạn chỉ định một tập hợp các vị trí nơi các mô hình của bạn được đặt và cũng cho phép bạn xác định một chức năng khớp tùy chỉnh để khớp với các tệp mô hình của bạn.

Việc sử dụng về cơ bản là như thế này:

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

Sau đó, bạn có thể truy cập vào các mô hình và sắp xếp lại như sau:

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

Hy vọng điều này sẽ giúp ai đó ra ngoài.


3
Liên kết đến một bài viết giúp một chút. Trích dẫn một số tài liệu là tốt hơn. Hiển thị một đoạn mã là tuyệt vời .... Nhưng thực sự xây dựng một thư viện giải quyết vấn đề và đưa nó lên NPM là điều tuyệt vời và xứng đáng được yêu thích hơn! +1 và sẽ đánh dấu sao cho dự án của bạn.
Stijn de Witt

9

Tôi bắt đầu sử dụng Sequelize trong ứng dụng Express.js. Ngay sau đó đã gặp phải các vấn đề về bản chất mà bạn mô tả. Có thể tôi không hoàn toàn hiểu Sequelize, nhưng với tôi làm nhiều việc hơn là chỉ chọn từ một bảng không thực sự tiện lợi. Và thông thường, bạn sẽ sử dụng select từ hai hoặc nhiều bảng hoặc liên kết trong SQL thuần túy, bạn sẽ phải chạy các truy vấn riêng biệt và với tính chất không đồng bộ của Node, nó chỉ tăng thêm độ phức tạp.

Vì vậy, tôi đã chuyển từ sử dụng Sequelize. Ngoài ra, tôi đang chuyển từ sử dụng BẤT K tìm nạp dữ liệu từ DB trong các mô hình. Theo tôi, tốt hơn hết là lấy dữ liệu trừu tượng hoàn toàn. Và lý do là - hãy tưởng tượng rằng bạn không chỉ sử dụng MySQL (trong trường hợp của tôi, tôi sử dụng MySQL và MongoDB cạnh nhau), nhưng bạn có thể lấy dữ liệu của mình từ bất kỳ nhà cung cấp dữ liệu và bất kỳ phương thức vận chuyển nào, ví dụ SQL, không SQL, hệ thống tập tin, API bên ngoài, FTP, SSH, v.v ... Nếu bạn đã cố gắng thực hiện tất cả trong các mô hình, cuối cùng bạn sẽ tạo mã phức tạp và khó hiểu, khó có thể nâng cấp và gỡ lỗi.

Bây giờ những gì bạn muốn làm là để có các mô hình lấy dữ liệu từ một lớp mà biết ở đâu và làm thế nào để có được nó, nhưng mô hình của bạn chỉ sử dụng phương pháp API, ví dụ như fetch, save,delete vv Và bên trong lớp này bạn phải triển khai cụ thể đối với các nhà cung cấp dữ liệu cụ thể. Ví dụ: bạn có thể yêu cầu một số dữ liệu nhất định từ tệp PHP trên máy cục bộ hoặc từ API Facebook hoặc từ Amazon AWS hoặc từ tài liệu HTML từ xa, v.v.

PS một số trong những ý tưởng được vay mượn từ kiến trúc sư của Cloud9 : http://events.yandex.ru/talks/300/


Đây là những điểm có hiệu lực, nhưng tôi thà tránh reimplementing fetch, save, delete, vv bên ngoài Sequelizecho rằng khuôn khổ đã được cung cấp các phương tiện. Nó đẹp hơn, nhưng ít thuận tiện hơn khi có một lớp tìm nạp riêng. Đồng thời, bạn có thể có thể thêm một lớp trừu tượng tìm nạp xung quanh Sequelize nhưng sau đó giải pháp phức tạp hơn, cho một chiến thắng có thể tranh cãi.
Zorayr

hướng dẫn này rất hữu ích: phần tiếp theo + ví dụ rõ ràng
Lucas Do Amaral

@ mvbl-fst Bạn vừa mô tả một lớp DAO. Giả sử bạn có một số người dùng trong SQL DB và những người dùng khác trên hệ thống tệp. Bạn nên có hai DAO tóm tắt cách lấy từng cái, sau đó một lớp nghiệp vụ kết nối người dùng với nhau (thậm chí có thể điều chỉnh một số thuộc tính) và chuyển chúng trở lại tuyến đường của bạn (lớp trình bày).
DJDaveMark

5

Tôi thiết lập nó như Farm và các tài liệu mô tả.

Nhưng tôi đã gặp vấn đề về phần bổ sung rằng trong các phương thức cá thể và các phương thức lớp mà tôi sẽ đính kèm vào các mô hình trong mỗi hàm, tôi sẽ cần phải yêu cầu tệp chỉ mục để có được các đối tượng cơ sở dữ liệu khác.

Giải quyết nó bằng cách làm cho chúng có thể truy cập được cho tất cả các mô hình.

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

Và trong tập tin mô hình

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

Tôi chỉ làm điều này cho các phương thức lớp nhưng bạn cũng có thể làm điều tương tự cho các phương thức ví dụ.


+1 cho classMethod nguyên mẫu đó trả về db. Chính xác là ý tưởng mà tôi đang tìm kiếm để có thể tải classMethod trong khi xác định nhưng cũng có thể tham chiếu bất kỳ Mô hình nào trong ClassMethod (nghĩa là bao gồm các mối quan hệ)
bitwit

2

Tôi đang làm theo hướng dẫn chính thức: http : // resultelizejs.com/heroku , có thư mục mô hình, thiết lập từng mô-đun trong các tệp riêng biệt và có tệp chỉ mục để nhập chúng và đặt mối quan hệ giữa chúng.


liên kết không hợp lệ
prisar

2

Mô hình mẫu sắp xếp lại

'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

Bạn có thể nhập mô hình từ các tệp khác với sequelize.import http://fterelizejs.com/documentation#models-import

Bằng cách đó, bạn có thể có một mô-đun singleton để sắp xếp lại, sau đó tải tất cả các mô hình khác.

Thật ra câu trả lời này khá giống với câu trả lời của user1778770.


1
điều này làm việc với các phụ thuộc tròn? Ví dụ: khi mô hình A có FK thành mô hình B và mô hình sẽ có FK để mô hình A
mkoryak

1

Tôi đang tìm kiếm một ứng dụng nodejs ví dụ sử dụng ORM tuần tự hóa.

Bạn có thể quan tâm đến việc xem xét giải pháp nồi hơi PEAN.JS.

PEAN.JS là một giải pháp mã nguồn mở JavaScript đầy đủ, cung cấp một điểm khởi đầu vững chắc cho các ứng dụng dựa trên PostgreSQL, Node.js, Express và AngularJS.

Dự án PEAN là một nhánh của dự án MEAN.JS (đừng nhầm với MEAN.IO hoặc ngăn xếp MEAN chung ).

PEAN thay thế MongoDB và Mongoose ORM bằng PostgreSQL và Sequelize. Một lợi ích chính của dự án MEAN.JS là tổ chức mà nó cung cấp cho một ngăn xếp có nhiều phần chuyển động.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.