Sequelize 4 - belongs-To-Many insert issue on eagger loading - mysql

Hi Folks, I have these two models:
const media = sequelize.define('media', {
id: { type: Sequelize.UUID, primaryKey: true, defaultValue: Sequelize.UUIDV4 },
name: { type: Sequelize.STRING, allowNull: false, unique:'compositeIndex' },}, { freezeTableName: true });
const mediaGenre = sequelize.define('mediaGenre', {
id: { type: Sequelize.UUID, primaryKey: true, defaultValue: Sequelize.UUIDV4 }}, { freezeTableName: true, name: { plural: 'mediaGenre' } });
and these two relations:
media.hasMany(mediaGenre, as: 'mGenre');
mediaGenre.belongsTo(media);
media.belongsToMany(genre, { through: mediaGenre });
genre.belongsToMany(media, { through: mediaGenre });
when I want to create a media I do:
MediaModels.media.create(
{name: 'Hulk',
mediaGenre: [
{ genreId: '021baab5-7fc6-4b06-aca5-e4b1ed1f3ce4' },
{ genreId: '03f069a4-dc52-4ab5-82d3-6bcd67d2d29e' }]},
{
include: [
{model: MediaModels.mediaGenre, as: 'mGenre'}
]
}
);
These has been working with sequelize 3 and recently I updated to sequelize 4.4.2 and it is not throwing error but the table mediaGenre it's not been populated.
Any ideas of what could be the error?

Have you tried to sync after you referenced the association? I had this issue and when i called to sync (with force false, this is important if tou dont want to erase your schema and to be recreated), the junction table was created.
If you are using sequelize-cli,also notice that in this version, classMethods are not longer supported. Instead, you shold add a method called associate directly to your model, which will be called in your models/index.js.

Related

Sequelize M:N association not creating through table record

When I create a recipe with associated tags using the through option, no record is created in the joining table in the mysql database I'm connected to.
Here are my models definitions:
export const Recipe = sequelize.define('Recipe', {
// Model attributes are defined here
title: {
type: DataTypes.STRING,
allowNull: false
},
image: {
type: DataTypes.STRING,
allowNull: true
},
prepTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
cookTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
totalTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
servings: {
type: DataTypes.INTEGER,
allowNull: false
},
rating: {
type: DataTypes.INTEGER,
allowNull: false
},
notes: {
type: DataTypes.STRING, allowNull: true
},
}, {
// Other model options go here
tableName: 'Recipes'
});
export const Tag = sequelize.define('Tag', {
// Model attributes are defined here
name: {
type: DataTypes.STRING,
allowNull: false
},
}, {
// Other model options go here
tableName: 'Tags'
});
export const RecipeTag = sequelize.define('RecipeTag', {
// Model attributes are defined here
}, {
// Other model options go here
timestamps: false,
tableName: 'RecipeTags'
});
Here are my associations:
Recipe.belongsToMany(Tag, {
through: RecipeTag,
foreignKey: 'recipeId',
as: 'tags'
})
Tag.belongsToMany(Recipe, {
through: RecipeTag,
foreignKey: 'tagId',
as: 'recipes'
})
Here is the create call:
Recipe.create(args, {
model: Tag,
through: RecipeTag,
as: 'tags'
});
And here is the data:
{
"title": "Test Recipe",
"image": "test",
"prepTime": 20,
"cookTime": 40,
"totalTime": 60,
"servings": 2,
"rating": 5,
"categoryId": 1,
"tags": [
{
"name": "New tag",
"id": 1
}
],
}
With this set up the create method only creates a new recipe. How can I use the create method to add a record to the joining RecipeTags table at the same time as creating a new recipe? I've managed to get it working by doing something like this:
args.tags.map(async (tag: { tagId: number }) => {
await RecipeTag.create({tagId: tag.tagId, recipeId: recipe.id})
});
But I'd rather have it done in the create if it's possible.
You need to wrap the association options with include.
Recipe.create(args, {
include: {
model: Tag,
through: RecipeTag,
as: 'tags'
}
});
UPDATE:
In order to prevent the duplicates, you can add ignoreDuplicates option and data must include the primary key value.
{
"title": "Test Recipe",
...
"tags": [
{
"name": "New tag",
"id": 1 # this is important
}
]
}
Then
Recipe.create(args, {
include: {
model: Tag,
through: RecipeTag,
as: 'tags',
ignoreDuplicates: true // Add this
}
});
There were some bugs for this option, I suggest you to use the newer version of Sequelize, if you haven't updated lately.

Sequelize M:N association not updating through table record

When I try to update a recipe with associated tags using the through option, no record is updated in the joining table in the mysql database I'm connected to.
Here are my models definitions:
export const Recipe = sequelize.define('Recipe', {
// Model attributes are defined here
title: {
type: DataTypes.STRING,
allowNull: false
},
image: {
type: DataTypes.STRING,
allowNull: true
},
prepTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
cookTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
totalTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
servings: {
type: DataTypes.INTEGER,
allowNull: false
},
rating: {
type: DataTypes.INTEGER,
allowNull: false
},
notes: {
type: DataTypes.STRING, allowNull: true
},
}, {
// Other model options go here
tableName: 'Recipes'
});
export const Tag = sequelize.define('Tag', {
// Model attributes are defined here
name: {
type: DataTypes.STRING,
allowNull: false
},
}, {
// Other model options go here
tableName: 'Tags'
});
export const RecipeTag = sequelize.define('RecipeTag', {
// Model attributes are defined here
}, {
// Other model options go here
timestamps: false,
tableName: 'RecipeTags'
});
Here are my associations:
Recipe.belongsToMany(Tag, {
through: RecipeTag,
foreignKey: 'recipeId',
as: 'tags'
})
Tag.belongsToMany(Recipe, {
through: RecipeTag,
foreignKey: 'tagId',
as: 'recipes'
})
Here is the update call:
Recipe.update(args, {
include: [{
model: Tag,
through: RecipeTag,
as: 'tags',
where: {
recipeId: args.id
}
}],
where: {
id: args.id
},
});
Only one update mysql call is executed on the Recipes table. Is it possible to update the RecipeTags through table record in the same update call?

nodejs sequelize: I can't update the primary key field's value

I can update every field's value except the id (primary key). It's for a website. I want to be able to update the id via the website.
module.exports = {
schema: function (sequelize, DataTypes) {
return sequelize.define(
'T_Event',
{
id: {
type: DataTypes.STRING,
primaryKey: true
},
user_id: {
type: DataTypes.STRING
},
name: {
type: DataTypes.STRING
},
created_at: {
type: DataTypes.DATE
},
description: {
type: DataTypes.STRING
},
image: {
type: DataTypes.STRING
},
closed_at: {
type: DataTypes.DATE
}
},
{
timestamps: true,
paranoid: true,
underscored: true,
freezeTableName: true
}
)
}
I'm using sequelize 3.33.0 with node and a MySQL database.
All attributes have select,insert & update privileges.
Sequelize restricts this kind of operation for security reasons. Usually updating a primary key through runtime with user provided information is a bad idea. It can lead to all sort of issues, especially if the changed object is being used by other users at the moment.
I follow the rule of thumb: if the column value can be changed, it is not a good candidate for a primary key. If there is no good candidate among all columns, create one with this sole purpose.
schema: function (sequelize, DataTypes) {
return sequelize.define(
'T_Event',
{
uid: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true
},
id: {
type: DataTypes.STRING,
unique: true
},
// ...
)
}
That said, there are cases where this kind of solution isn't doable. In that case, you may use a workaround, making an update that changes the id:
T_Event.update(
{
id: new_value
}, {
where: {
uid: current_value
}
}
);

sequelize - how to update an association in n-m relation including join table

I have two tables (user, tag) that are connected to each other with a belongsToMany relationship through a join entity (user_tag):
sequelize.define('tag', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
type: {
type: DataTypes.STRING
}
}, {
classMethods: {
associate: function (models) {
this.belongsToMany(models.user, {as: "users", through: models.user_tag });
},
}
}
sequelize.define('user', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
name: {
type: DataTypes.STRING,
},{
classMethods: {
associate: function (models) {
this.belongsToMany(models.tag, { as:"tags", through: models.user_tags });
}
}
}
sequelize.define('user_tag', {
type: DataTypes.STRING,
param1: DataTypes.INTEGER,
priority: DataTypes.INTEGER
}, {
freezeTableName: true,
paranoid: true
});
Now, a user can update all his tags, including all the specific information on the join entity (user_tag) for example priority and param1.
I'm aware of setAssociation [ e.g. user.setTag(myTags) ], however, how do I set the matching param1 and priority properties?
According to Sequelize's documentation when adding a new relationship with belongsToMany, you can pass in additional attributes to the option object and that data will get added to the through model.
user.setTag(myTags, { param1: 1, priority: 1 });

Prevent SailJS waterline to create columns which are used for association

I am new to NodeJs/sailsJS.
I have following models:
Person
module.exports = {
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
person_id: {
type: 'integer',
primaryKey: true,
autoIncrement: true
},
user: {
model: 'user'
},
person_name: {
type: 'string',
required: true,
size: 128
},
person_birthdate: {
type: 'date'
},
person_gender: {
type: 'string',
size: 1
}
}
};
User
module.exports = {
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
user_id: {
type: 'integer',
primaryKey: true,
autoIncrement: false
},
person: {
model: 'person'
}
}
};
It creates column person in user table and column user in person table. How do I stop these columns to pop up and still be able to use waterline. Entity Framework in C# MVC is able to provide that functionality, so I think there might be a way to do it in SailsJs.
Try to add in file config/models.js this line: migrate: 'safe' to exported configuration.
About model settings you can read here: sailsjs.org/documentation