Search code examples
node.jssequelize.jsassociationsapollo

Apollo, Sequelize - Simple `belongsTo` association returns null


Trying to setup a simple association in sequelize for my apollo graphql api. I have two tables: user and role. Each user has a role_id column that references the primary keys in the role table.

Whenever I query:

{
  users{
    id,
    email,
    role{
      id
    }
  },
}

I receive the following error: "Cannot return null for non-nullable field User.role.",

I am new to sequelize/apollo, but am unable to see where I am going wrong.

models/user.js

'use strict';

const { Model } = require('sequelize');

module.exports = (sequelize, DataTypes) => {
  class User extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
      User.belongsTo(models.Role);
    }
  };

  User.init({
    email: DataTypes.STRING,
    password: DataTypes.STRING,
  }, {
    sequelize,
    tableName: 'user',
    schema: 'auth',
    modelName: 'User',
    timestamps: false,
    underscored: true,
  });

  return User;
};

models/role.js

'use strict';

const { Model } = require('sequelize');

module.exports = (sequelize, DataTypes) => {
  class Role extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
      Role.hasMany(models.User)
    }
  };

  Role.init({
    name: DataTypes.STRING,
    isDefault: {
      type: DataTypes.BOOLEAN,
      field: 'is_default'
    },
  }, {
    sequelize,
    tableName: 'role',
    schema: 'auth',
    modelName: 'Role',
    timestamps: false,
    underscored: true,
  });

  return Role;
};

The models get associated in my: models/index.js with the following snippet:

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

// sync models - modifies the database to match every model
sequelize.sync({ alter: true, match: /-apollo$/ })
...

And here is my: resolvers/user.js

module.exports = {
  Query: {
    users: async (parent, args, { models }) => {
      return await models.User.findAll({ include: [{model: models.Role}] });
    },
    user: async (parent, { id }, { models }) => {
      return await models.User.findByPk(id);
    },
  },
};

Any help would be much appreciated!

Edit: I created a new database and added sequelize.sync() to my models/index.js to ensure that this is not caused by some error in my database setup.


Solution

  • Found the solution. My issue was that sequelize automaticly names the association, which in my case was unexpected and so my schema didn't match the actual name of the association which resulted in nulls.

    To fix this I added the as: "something" prop to my association:

    resolvers/user.js

    module.exports = {
      Query: {
        users: async (parent, args, { models }) => {
          return await models.User.findAll({ include: [{model: models.Role, as: 'role'}] });
        },
        user: async (parent, { id }, { models }) => {
          return await models.User.findByPk(id);
        },
      },
    };