简体   繁体   中英

Sequelize Many-to-Many eager loading on pre-existing DB

I am attempting to setup my existing Express app with Sequelize. In the application, upon a user logging in, I perform a query to try to obtain an object that represents the user and several of the relations from a handful of tables. I have drawn my test down to the following minimized representation using a Many-to-Many relationship.

This is my User model (in coffeescript):

module.exports = (sequelize, DataTypes) ->
  sequelize.define "User",
    id:
      type: DataTypes.INTEGER(11)
      primaryKey: true
      autoIncrement: true

    email:
      type: DataTypes.STRING
      allowNull: false

  ,
    tableName: 'users'
    classMethods:
      associate: (models) ->
        @hasOne models.UserDetail
        @hasMany models.Plan,
          through: models.UserPlan
          foreignKey: 'user_id'

This is my Plan model:

module.exports = (sequelize, DataTypes) ->
  sequelize.define "Plan",
    id:
      type: DataTypes.INTEGER(11)
      primaryKey: true
      autoIncrement: true

    plan:
      type: DataTypes.STRING
      allowNull: false
  ,
    tableName: 'plans'
    classMethods:
      associate: (models) ->
        @hasMany models.User,
          through: models.UserPlan
          foreignKey: 'plan_id'

And, this is the intermediate 'through' table (user_plans):

module.exports = (sequelize, DataTypes) ->
  sequelize.define "UserPlan",
    user_id:
      type: DataTypes.INTEGER(11)
      allowNull: false
      primaryKey: true

    plan_id:
      type: DataTypes.INTEGER(11)
      allowNull: false
  ,
    tableName: 'user_plans'

Here is the find that I'm executing that I was hoping to get this working:

          console.log JSON.stringify(u)
          db.User.find(
            where:
              id: u.id
            include: [
                model: db.Plan
                as: 'plan'
            ]
          )
          .success (user) ->
            console.log JSON.stringify(user)

In this case, I have a non-eager loaded object 'u' that gets dropped to the console, but then post-query .success call never happens, so the 'user' object never gets dumped to the console. Here is the output:

{"id":3,"email":"asdf@1234.com"}
[Error: Plan (plan) is not associated to User!]

Any idea what I could be doing wrong? Some poking around shows that this may have been a problem in the past with existing tables, but it looks like those problems have been resolved in the latest versions of sequelize. I am running ~1.7.0 (latest at the time of this writing).

Any help is appreciated.

The as in includes specify an alias. This alias also has to be set when you set up the association.

A couple of examples:

User.hasMany(Plans) 
User.find({
  include: [
    { model: Plan }  // no as is allowed here, since we didnt specify it in the association
  ]
})

User.hasMany(Plans, { as: 'plans' }) 
User.find({
  include: [
    { model: Plan, as: 'plans' } // here you HAVE to specify the same alias as you did in your association
  ]
})

As a bit more advanced example, showing why the as is necessary, consider the same model being associated multiple times:

User.belongsTo(Plans, { as: 'currentPlans' }) // this is joined via planId on user
User.hasMany(Plans, { as: 'previousPlans' }) // this is stored in a join table
Plan.hasMany(User)

User.find({
  include: [
    { model: Plan } 
      /* If you dont specify an as here, sequelize has no way of knowing which 
         relation to load. Therefore the as should only be provided if you 
         set one in the association, and you should provide the exact same
         string as in the assocation.
      */ 
  ]
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM