0

I'm using NodeJS and sequelize. I have user table with a column named duel_id, and each user can be assigned to one duel at a time. Each duel can have multiple users in it.

I have the following User Model:

const User = Model.define(
  'User',
  {
    user_id: {
      type: DataType.INTEGER,
      primaryKey: true,
    },

    username: {
      type: DataType.STRING(255),
    },
    character: {
      type: DataType.INTEGER,
    },
    duel_id: {
      type: DataType.INTEGER,
    },
  },
  {
    indexes: [{ fields: ['user_id', 'username'] }],
    tableName: 'users',
    timestamps: false,
  },
);

User.hasOne(Duel, { as: 'duel', foreignKey: 'id', sourceKey: 'duel_id' });

with the following Duel model:

const Duel = Model.define(
  'DuelRoom',
  {
    id: {
      type: DataType.INTEGER,
      primaryKey: true,
      autoIncrement: true,
    },
    round_id: {
      type: DataType.INTEGER,
    },
    status: {
      type: DataType.STRING,
    },
    turn_of_user_id: {
      type: DataType.INTEGER,
    },
    winner: {
      type: DataType.STRING,
    },
  },
  {
    indexes: [{ fields: ['id'] }],
    tableName: 'duel_rooms',
    timestamps: true,
  },
);

The above code works and return the user and the associated duel if he has one.

I want also to return all the users associate to the same duel.

I tried to connect the relationship with hasMany/ belongsTo with no success. The following errors appears:

Error: DuelRoom.hasMany called with something that's not a subclass of Sequelize.Model

I want to be able to query to get the data like this:

user: { 
   user_id,
   username
   duel: {
      round_number
      players: [{user_id, username}]
   }
}

Get the current user with the duel info, with all players associated with the same duel_id as an array named players.

Any idea of how I can define such a relation using sequelize to return all users associated to the user duel?

TheUnreal
  • 23,434
  • 46
  • 157
  • 277

2 Answers2

1

If a User model has dual_id then you should use belongTo from User to DualRoom instead of hasOne:

User.belongsTo(Duel, { as: 'duel', foreignKey: 'duel_id' });

If you wish to have users collection in a Duel model then this will work with the following hasMany:

Duel.hasMany(User, { as: 'users', foreignKey: 'duel_id' });

Take into account that you should register all associations AFTER all model registrations like I advised in this answer

After all this setup you can get what you wish by executing a query like this:

const user = await User.findOne({
  where: {
     user_id: id
  },
  include: [{
    model: Duel,
    as: 'duel',
    include: [{
      model: User,
      separate: true,
      as: 'users'
    }]
  }]
})
Anatoly
  • 20,799
  • 3
  • 28
  • 42
  • Thanks, but how I can import `User` and `Duel`, it creates a circular dependency and return undefined since the associated model is not defined yet, any idea? – TheUnreal Sep 20 '20 at 10:14
  • Did you look at my answer with a link I got you https://stackoverflow.com/questions/61709290/sequelize-model-association-wont-create-a-new-column/61710568#61710568 – Anatoly Sep 20 '20 at 10:17
  • I took a look, If I need to refactor all my sequelize code and add code to scan directories and files just for making relationships work in ORM, I rather not use it. Thanks. – TheUnreal Sep 20 '20 at 10:36
  • You can manually register models and associations in one module importing them explicitly if you don't wish to scan directories. – Anatoly Sep 20 '20 at 11:01
  • Thanks @Anatoly. It solved the issue - but got last one. In my question I asked for `players` (which is a `User` list). I set it up in GraphQL but not sure how to add the user list which belongs to the user duel here: `return await User.findByPk(id, { include: 'duel' });`. Any idea? – TheUnreal Sep 20 '20 at 13:44
  • 1
    If you wish to name users of a certian duel as `players` then just rename alias `Duel.hasMany(User, { as: 'players', foreignKey: 'duel_id' });` and then change `as: 'users'` to `as: 'players'` in the query itself – Anatoly Sep 20 '20 at 14:35
0

As each user can have a duel and one duel can be associated with many users. It is a one-to-many association, so, you should try:

Duel.hasMany(User);
User.belongsTo(Duel);
kavigun
  • 2,219
  • 2
  • 14
  • 33