Sequelize model loading in NodeJS

时间:2018-03-25 19:27:03

标签: node.js sequelize.js

I am currently studying using NodeJS, Express, PostgreSQL and Sequelize on Scotch.io then I came across this:

'use strict';

var fs        = require('fs');
var path      = require('path');
var Sequelize = require('sequelize');
var basename  = path.basename(module.filename);
var env       = process.env.NODE_ENV || 'development';
var config    = require(__dirname + '/../config/config.json')[env];
var db        = {};

if (config.use_env_variable) {
  var sequelize = new Sequelize(process.env[config.use_env_variable]);
} else {
  var sequelize = new Sequelize(config.database, config.username, config.password, config);
}

fs
  .readdirSync(__dirname)
  .filter(function(file) {
    return (file.indexOf('.') !== 0) && (file !== basename) & (file.slice(-3) === '.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].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

module.exports = db;

I need someone to please help explain these in plain terms. What exactly is happening here?

I do understand the part where we default to development is Node environment is not set but I really need clarification of the file reading part i.e where fs begins.

Thanks a lot.

2 个答案:

答案 0 :(得分:7)

Firstly, note that this code is generated by sequelize-cli by running sequelize init and is placed in a file called index.js located in a models/ folder.

1. The Configuration Environment

if (config.use_env_variable) {
  var sequelize = new Sequelize(process.env[config.use_env_variable]);
} else {
  var sequelize = new Sequelize(config.database, config.username, config.password, config);
}

This is helpful for when in production. As an example, I'll show you my code:

module.exports = {
  development: {
    dialect: 'postgres',
    username: '<username name>',
    password: 'test',
    database: '<db name>',
    host: 'localhost'
  },
  production: {
    dialect: 'postgres',
    dialectOptions: {
      ssl: true
    },
    protocol: 'postgres',
    use_env_variable: 'DATABASE_URL'
  }
}

Heroku sets a process variable DATABASE_URL that I simply point to. The username, password etc are obtained from this, rather than listing them explicitly in config.js, as development credentials are.

2. Importing/Reading Models

fs
  .readdirSync(__dirname)
  .filter(function(file) {
    return (file.indexOf('.') !== 0) && (file !== basename) & (file.slice(-3) === '.js');
  })
  .forEach(function(file) {
    var model = sequelize['import'](path.join(__dirname, file));
    db[model.name] = model;
  });

fs.readdirSync synchronously reads the directory given in its argument. In this case, it's __dirname, which is the directory that this index.js file is in. Here, the models you defined in models/ directory are pulled in. Notice that the filter function is just making sure that:

  • There are files to read
  • It excludes this file (ie not index.js)
  • They end in '.js'

Each model file is then keyed into the exports Object with the line db[model.name] = model;

3. Associating Each Model

Object.keys(db).forEach(function(modelName) {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

module.exports = db;

Lastly, once we have obtained all of the model files (from the previous read), we run each model's associate function, if it exists. This is a method that's defined in each model file as follows:

module.exports = (sequelize, DataTypes) => {
  var Model1 = sequelize.define('Model1',
    { ... })

  // Class Method
  Model1.associate = function (models) {
    Model1.belongsTo(models.Model2)
  }
  return Model1
}

4. Exported Use

Both an instance of your sequelize database (sequelize) and an instance of the Sequelize library are exported.

In this manner we can now do the following:

assume a directory structure of

  • models/
    • index.js
    • model1.js
    • model2.js

require('./models').Model1 // access to your models

This is how you'll import and use your models, rather than directly through their definition files. This ensures they're synced and associated properly.

Likewise we have access to sequelize:

require('./models')
  .sequelize.sync({ force: true }) // access to your sequelize db

答案 1 :(得分:1)

In plain terms, this is importing all the .js files from the same directory as this file. This is done through sequelize['import'] method.

Moreover it is assumed that all these files contain sequelize models, as the return value from the import is mapped on dictionary named db.

db[model.name] = model

Once all the files are imported and models are mapped to db, a loop is run to call associate on each model, only if that model contains associate method. Usually associate method is used to define all the associations between the models i.e. hasMany, hasOne, belongsTo etc.