Pradeep Rajashekar
Pradeep Rajashekar

Reputation: 575

Sequelize - Associating 4 tables

Am trying to associate 4 tables. Tasks, TaskQuestions, Questions and Options.

enter image description here

My models are as follows

Tasks model:

var Sequelize = require('sequelize');

module.exports = function(sequelize, DataTypes) {
  var Task = sequelize.define('Task', {
    task_id: {
      type: Sequelize.STRING,
      primaryKey: true
    },
    task_name: {
      type: Sequelize.STRING,
      allowNull: true
    },
    task_description: {
      type: Sequelize.STRING,
      allowNull: true
    }
  },{
    classMethods: {
      associate: function(models) {
        Task.belongsToMany(models.Question, {
          through: {
            model: models.TaskQuestion
          },
          foreignKey: 'task_id'
        })
      }
    }
  });
  return Task;
};

TaskQuestions model:

var Sequelize = require('sequelize');

module.exports = function(sequelize, DataTypes) {
  var TaskQuestion = sequelize.define('TaskQuestion', {
    tq_id: {
      type: Sequelize.STRING,
      primaryKey: true
    }
  });
  return TaskQuestion;
};

Questions model:

var Sequelize = require('sequelize');

module.exports = function(sequelize, DataTypes) {
  var Question = sequelize.define('Question', {
    question_id: {
      type: Sequelize.STRING,
      primaryKey: true
    },
    question_description: {
      type: Sequelize.STRING,
      allowNull: true
    },
    question_type: {
      type: Sequelize.STRING,
      allowNull: true
    }
  },{
    classMethods: {
      associate: function(models) {
        Question.hasMany(models.Option, {
          foreignKey: {
            name: 'question_id',
            allowNull: false
          }
        }),
        Question.belongsToMany(models.Task, {
            through: {
                model: models.TaskQuestion
            },
            foreignKey: 'question_id'
        })
      }
    }
  });
  return Question;
};

Options model:

var Sequelize = require('sequelize');

module.exports = function(sequelize, DataTypes) {
  var Option = sequelize.define('Option', {
    option_id: {
      type: Sequelize.STRING,
      primaryKey: true
    },
    question_id: {
      type: Sequelize.STRING,
      allowNull: true
    },
    option_description: {
      type: Sequelize.STRING,
      allowNull: true
    },
    option_type: {
      type: Sequelize.STRING,
      allowNull: true
    }
  },{
    classMethods: {

    }
  });
  return Option;
};

When I try to retrieve the data

router.get('/:task_id', function(req, res) {
  models.Task.findOne({
    where: {
      task_id: req.params.task_id
    },
    include: [ models.Question ]
  }).then(function(task) {
    res.json(task);
  });
});

All I get is the association between Task and Questions. When I retrieve Questions individually I get Options under it. But can't seem to retrieve all at once.

Is it even possible. And let me know if am following the right approach designing the database in this format.

I need one task to contain multiple questions and same questions can appear in multiple tasks. Each question should contain multiple options.

Upvotes: 0

Views: 753

Answers (1)

joshua.paling
joshua.paling

Reputation: 13952

Yes, it's possible, and is covered in the documentation at http://docs.sequelizejs.com/en/latest/docs/models-usage/#nested-eager-loading

Basically, rather than putting a model like models.Question in your include array, you put an object, with a key for model and a key for the nested include's

For your example above, something like this should do the trick:

router.get('/:task_id', function(req, res) {
  models.Task.findOne({
    where: {
      task_id: req.params.task_id
    },
    include: [{
      model: models.Question,
      include: [models.Option]
    }]
  }).then(function(task) {
    res.json(task);
  });
});

Upvotes: 1

Related Questions