Guilherme L. Moraes
Guilherme L. Moraes

Reputation: 122

How to use findAll with associations in Sequelize

I'm having problems to use the findAll() method with associations from Sequelize. I have two models: Posts and Authors (an author has many posts and one post has one author), that I have created with Sequelize-cli and then through the migration command npx sequelize db migrate:all i have created them in mysql. To keep things organized, I have the associations between the models in another migration file (created with npx sequelize init:migrations, after all the models already existent), so my code looks like this:

AUTHOR MODEL

'use strict';
module.exports = (sequelize, DataTypes) => {
  const Author = sequelize.define('Author', {
    authorName: { 
      type: DataTypes.STRING,
      validate: {
        is: ["^[a-z]+$",'i'], 
      }
    },
    biography: {
      type: DataTypes.TEXT,
      validate: {
        notEmpty: true,
      }
    }
  }, {});
  Author.associate = function(models) {
    Author.hasMany(models.Post);
  };
  return Author;
};

POST MODEL

'use strict';
module.exports = (sequelize, DataTypes) => {
  const Post = sequelize.define('Post', {
    title: { 
      type: DataTypes.STRING,
      validate: {
        is: ["^[a-z]+$",'i'],
        notEmpty: true,
      },
    },
    content: { 
      type: DataTypes.TEXT,
      validate: {
        notEmpty: true,
      },
    },
    likes: {
      type: DataTypes.INTEGER,
      defaultValue: 0,
      validate: {
        isInt: true,  
      },
    },
  }, {});
  Post.associate = function(models) {
    // associations can be defined here
  };
  return Post;
};

ASSOCIATIONS FILE (MIGRATION) (showing only parts that matter)

up: (queryInterface, Sequelize) => {
    return queryInterface.sequelize.transaction(t => {
      return Promise.all([
        queryInterface.addColumn('Posts','AuthorId', {
            type: Sequelize.INTEGER,
            references: {
              model: 'Authors',
              key: 'id',
            },
            onUpdate: 'CASCADE',
            onDelete: 'SET NULL',
        }, { transaction: t }),
        queryInterface.addColumn('Posts', 'ImagesId', {
            type: Sequelize.INTEGER,
            references: {
              model: 'Images',
              key: 'id',
            },
            onUpdate: 'CASCADE',
            onDelete: 'SET NULL',
        }, { transaction: t }),
        queryInterface.addColumn('Posts', 'CategoryId', {
          type: Sequelize.INTEGER,
          references: {
            model: 'Categories',
            key: 'id',
          },
          onUpdate: 'CASCADE',
          onDelete: 'SET NULL',
        }, { transaction: t }),
      ]);
    });

This is working fine apparently, since in Mysql-Workbench it shows me the following: forget about the images and categories

But, when I try to use the findAll() like this:

const { Post, Author } = require('../models/index');

function(response) {
   Post.findAll({ 
      attributes: ['id', 'title', 'content', 'likes'],
      include: {
        model: Author,
      }
   })
   .then(result => response.json(result))
     .catch(error => response.send(`Error getting data. Error: ${error}`));

It gives me the following error:

SequelizeEagerLoadingError: Author is not associated to Post!

So, I dont know anymore how to proceed. I've been trying many others approaches, but all of then unsuccessfully. I read already many other questions here in StackOverFlow about how to solve this sort of problem, but those were unsuccessfully too.

Thanks in advance.

Upvotes: 0

Views: 2396

Answers (2)

Summarizing this documentation we have the following:

If you have these models:

const User = sequelize.define('user', { name: DataTypes.STRING });
const Task = sequelize.define('task', { name: DataTypes.STRING });

And they are associated like this:

User.hasMany(Task);
Task.belongsTo(User);

You can fetch them with its associated elements in these ways:

const tasks = await Task.findAll({ include: User });

Output:

[{
  "name": "A Task",
  "id": 1,
  "userId": 1,
  "user": {
    "name": "John Doe",
    "id": 1
  }
}]

And

const users = await User.findAll({ include: Task });

Output:

[{
  "name": "John Doe",
  "id": 1,
  "tasks": [{
    "name": "A Task",
    "id": 1,
    "userId": 1
  }]
}]

Upvotes: 1

Vivek Doshi
Vivek Doshi

Reputation: 58533

You need to define the association for Post also as you are querying upon Post model

Post.associate = function(models) {
  Post.belongsTo((models.Author);
};

You need to add an association from both ends, Post -> Author and Author -> Post , this way you will never stuck in this kind of error.

Upvotes: 1

Related Questions