4

I have two models: Article and DescriptionFragment in a BelongsToMany association through a join table Descriptions, which in turn BelongsTo another model Category and also has an attribute "sequence", all defined as follows:

Article model:

'use strict';
module.exports = (sequelize, DataTypes) => {
  const Article = sequelize.define('Article', {
    uid: {
      type: DataTypes.INTEGER,
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
      field: 'uid'
    },
    articleNumber: {
      type: DataTypes.INTEGER(8),
      allowNull: false,
      field: 'article_number',
      unique: true
    },
  }, {
    underscored: true,
  });
  Article.associate = function (models) {
    Article.belongsToMany(models.DescriptionFragment, {
      through: 'Descriptions',
      as: 'articleWithDescriptionFragment',
      otherKey: {
        name: 'descriptionFragmentId',
        field: 'description_fragment_id'
      },
      foreignKey: {
        name: 'articleId',
        field: 'article_id'
      },
      onDelete: 'CASCADE',
      onUpdate: 'CASCADE'
    });
  };
  return Article;
};

DescriptionFragment model:

'use strict';
module.exports = (sequelize, DataTypes) => {
  const DescriptionFragment = sequelize.define('DescriptionFragment', {
    uid: {
      type: DataTypes.INTEGER,
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
      field: 'uid'
    }
  }, {
    charset: 'utf8',
    dialectOptions: {
      collate: 'utf8_general_ci'
    },
    timestamps: true,
    paranoid: true,
    underscored: true,
  });
  DescriptionFragment.associate = function (models) {
    DescriptionFragment.belongsToMany(models.Article, {
      through: 'Descriptions',
      as: 'descriptionFragmentForArticle',
      foreignKey: {
        name: 'descriptionFragmentId',
        field: 'description_fragment_id'
      },
      otherKey: {
        name: 'articleId',
        field: 'article_id'
      },
      onDelete: 'CASCADE',
      onUpdate: 'CASCADE'
    });
  };
  return DescriptionFragment;
};

Description model:

'use strict';
module.exports = (sequelize, DataTypes) => {
  const Description = sequelize.define('Description', {
    sequence: {
      type: DataTypes.INTEGER,
      allowNull: true
    }
  }, {
    charset: 'utf8',
    dialectOptions: {
      collate: 'utf8_general_ci'
    },
    timestamps: true,
    paranoid: true,
    underscored: true,
  });
  Description.associate = function (models) {
    Description.belongsTo(models.Category, {
      as: 'categoryDescription',
      foreignKey: {
        name: 'categoryId',
        field: 'category_id'
      },
      targetKey: 'uid',
      onDelete: 'CASCADE',
      onUpdate: 'CASCADE'
    });
  };
  return Description;
};

Category model:

'use strict';
module.exports = (sequelize, DataTypes) => {
  const Category = sequelize.define('Category', {
    uid: {
      type: DataTypes.INTEGER,
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
      field: 'uid'
    }
  }, {
    charset: 'utf8',
    dialectOptions: {
      collate: 'utf8_general_ci'
    },
    timestamps: true,
    paranoid: true,
    underscored: true,
  });
  Category.associate = function (models) {
    Category.hasMany(models.Description, {
      foreignKey: {
        name: 'categoryId',
        field: 'category_id'
      },
      sourceKey: 'uid',
      onDelete: 'CASCADE',
      onUpdate: 'CASCADE'
    });
  };
  return Category;
};

My problem comes when I try to associate a DescriptionFragment to an Article. I'm using the following code:

let addedArticle = await Article.create(newArticle);

addedArticle.addArticleWithDescriptionFragment(descFrag, {
    through: {
      categoryId: catId,
      sequence: index
    }
  });

where descFrag is an instance of the DescriptionFragment model, and catId and index are integers.

When that code is run, sequelize creates the Article instance addedArticle, but then when trying to associate it to DescriptionFragment it just ignores what is in the through option. The SQL generated is, for example:

Executing (default): INSERT INTO "devdb"."Descriptions" ("created_at","updated_at","article_id","description_fragment_id") VALUES ('2019-02-07 15:11:15.376 +00:00','2019-02-07 15:11:15.376 +00:00',95,5);

As far as I could find in the documentation, the syntax I'm using is correct, and the association is created in the Descriptions table, just with null for sequence and category_id.

I'm using sequelize v4.38.1 and the database is Postgres.

I can't spot where is the error and all similar issues I have found so far were just using in sequelize v4 the old syntax for v3.

Any insight would be appreciated, thanks!


UPDATE

For now I'm using the following workaround:

await addedArticle.addArticleWithDescriptionFragment(descFrag);
let newDesc = await models.Description.find({
  where: { articleId: addedArticle.uid, descriptionFragmentId: descFrag.uid }
});
await newDesc.update({ categoryId: catId, sequence: index });

which correctly sets the desired columns:

Executing (default): UPDATE "techred_dev"."Descriptions" SET "category_id"=2,"sequence"=0,"updated_at"='2019-02-08 09:21:20.216 +00:00' WHERE "article_id" = 104 AND "description_fragment_id" = 6

Of course for this to work I had to update my Description model explicitly adding the articleId and descriptionFragmentId columns:

articleId: {
  type: DataTypes.INTEGER,
  onDelete: 'CASCADE',
  onUpdate: 'CASCADE',
  references: {
    model: 'Articles',
    key: 'uid'
  },
  primaryKey: true,
  field: 'article_id'
},
descriptionFragmentId: {
  type: DataTypes.INTEGER,
  onDelete: 'CASCADE',
  onUpdate: 'CASCADE',
  references: {
    model: 'DescriptionFragments',
    key: 'uid'
  },
  primaryKey: true,
  field: 'description_fragment_id'
},

Still, the 'through' option in the 'add' method does not work and I have no clue why.

Javad
  • 81
  • 7

0 Answers0