Question

I am attempting to migrate a PHP website over to Node.js and I'm now looking at setting up the databases with Sequelize.

The majority of the tables are set up OK but I'm having trouble figuring out how to do normalization.

E.g. I have 1 database Users:

ID
Username
Email
Password

And another table called Domains:

ID
Domain
RegisteredAt

And now I need to create a 3rd table to link to the 2 tables together for lookups like so:

UserID
DomainID

I have tried setting up OneToOne associations from the Sequelize documentation, but this just seems to create an extra field in the original 2 tables. Could someone explain how I'd do this please?

Thanks for any help

Was it helpful?

Solution

@ Samuel Neff

In case you're still interested in the answer, this is how I do it using an example of Users and Jobs, as of Sequelize version 2.0.0-rc2:

index.js

This was taken from the Sequelize website, although I can't seem to find it on there now but it still works fine. It scans through the models directory and loads all models that are kept in separate files.

var fs        = require('fs')
  , path      = require('path')
  , Sequelize = require('sequelize')
  , lodash    = require('lodash')
  , db_config    = require('../../config').database
  , sequelize = new Sequelize(db_config.db_name, db_config.db_user, db_config.db_password)
  , 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 ('associate' in db[modelName]) {
    db[modelName].associate(db)
  }
})

module.exports = lodash.extend({
  sequelize: sequelize,
  Sequelize: Sequelize
}, db)

_userjobs.js

This filename begins with an underscore because it HAS to be loaded first, as it's the normalization table.

module.exports = function(sequelize, DataTypes) {
  var job_user = sequelize.define('job_user', {
    custom_field: DataTypes.STRING
  });

  return job_user;
}

user.js

A simple model declaration, with an association defined.

module.exports = function(sequelize, DataTypes) {
  var user = sequelize.define('user', {
    username: DataTypes.STRING,
    password: DataTypes.STRING,
    email: DataTypes.STRING,
    first_name: DataTypes.STRING,
    surname: DataTypes.STRING,
    postcode: DataTypes.STRING,
    gender: DataTypes.STRING,
    facebook_id: DataTypes.STRING,
    twitter_id: DataTypes.STRING,
    user_rank: DataTypes.STRING,
    generated_username: DataTypes.BOOLEAN,
    forgot_password: DataTypes.STRING
  }, {
    classMethods: {
      associate: function(models) {
        user.hasMany(models.job, {through: models.job_user});
      }
    }
  });

  return user;
}

jobs.js

Another simple model declaration.

module.exports = function(sequelize, DataTypes) {
  var job = sequelize.define('job', {
    name: DataTypes.STRING,
    description: DataTypes.TEXT
  }, {
    classMethods: {
      associate: function(models) {
        job.hasMany(models.user, {through: models.job_user});
      }
    }
  });

  return job;
}

If you run your app, you will end up with 3 tables: users, jobs & job_users, with the latter containing both userId and jobId for normalization.

You don't necessarily need the _userjobs.js file, but this is required if you want to add extra fields to the table, such as 'custom_field' in my example. If you don't need additional fields, simply delete that file and change:

user.hasMany(models.job, {through: models.job_user});

and

job.hasMany(models.user, {through: models.job_user});

to:

user.hasMany(models.job, {through: 'job_users'});

and

job.hasMany(models.user, {through: 'job_users'});

Hope that helps!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top