Sequelize Migration - change already existing primary key to autoincrement - javascript

I am trying to change an already existing primary key (id) to be changed to autoincrement through Sequelize Migration. Following is what I tried but didnt quite work. I tried removing the constraint, making changes to the column and adding the constraint again.
module.exports = {
up: async (queryInterface, Sequelize) => {
queryInterface.removeConstraint('category', 'category_pkey')
.then(() => {
queryInterface.changeColumn('category', 'id', {
type: Sequelize.DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
}).then(() => {
queryInterface.addConstraint('category', 'category_pkey', {
fields: ['id'],
type: "primary key",
name: 'category_pkey'
});
})
})
},
async down(queryInterface, Sequelize) {
}
};

Related

Is there a way to set 'expires' option in Sequelize timestamps just like Mongoose?

const sequelize = require("../config/sequelize");
const Sequelize = require("sequelize");
const Token = sequelize.define('token', {
token: {
type: Sequelize.STRING,
allowNull: false
},
createdAt: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW
expires: 43200
}
})
Can I add expires option like in the above code in Sequelize?
#ayindesamuel why don't you create the tokenExpires key directly inside your sequelize model? Also, including a third object allows you to turn on timestamps (createdAt and updatedAt) these columns will be automatically added by sequelize. So you don't have to manually create the Key.
const sequelize = require("../config/sequelize");
const Sequelize = require("sequelize");
const Token = sequelize.define('token', {
token: {
type: Sequelize.STRING,
allowNull: false
},
tokenExpires : {
type: Sequelize.DATE,
defaultValue: Date.now() + 43200
}
}, { timestamps : true })

How to set a column of a table as a foreign key using sequelize.js

What I'm trying to achieve is: when a new competition is added, I need to create a row in the the table team_comp conteining the same id of field "competition_teams" of table competition and the extra data that i send by request. I'll have a lot of competitions but each competition has one team_comp that belongs to it. If i delete a competition, its team_comp row must be deleted.
table competition:
| id | name | competition_teams |
| 1 | A | 32 |
table team_comp:
| id | competition_id | test_h |
| 3 | 32 | 1 |
In my models/index.js I'm defining associations like this:
// Competition
db.competition.hasOne(db.competition_team, {as: 'compId', foreignKey : 'competition_id'});
// Competition Teams
db.competition_team.belongsTo(db.competition, {as: 'compTeam', foreignKey : 'competition_id', onDelete: 'CASCADE'});
By doing this, I get the wrong foreign key. It creates me a foreign key in table ** team_comp ** pointing to competion.id and not into competition.competition_teams (which is what i want).
How can I let it points to competition.competition_teams?
This is how I add a new competition (controllers/ competition.js):
import db from '../models/index';
const Competition = db.competition;
const Competition_teams = db.competition_team;
// create competition
const create = (req, res) => {
// generating a random id for the competition
var competition_teams = Math.floor(Math.random() * 100);
let {
name,
test_h,
} = req.body;
// create new Competition
let newCompetition = {
name,
competition_teams // this must be also added in table team_comp, column competition_id
}
let newCompetitionTeams = {
test_h
}
Competition.create(newCompetition)
.then(Competition => {
res.json({ Competition });
})
.catch(err => {
console.log("Error: " + err);
return res.status(500).json({ err });
});
// creating teams association
Competition_teams.create(newCompetitionTeams)
.then(Competition_teams => {
res.json({ Competition_teams });
})
.catch(err => {
console.log("Error: " + err);
return res.status(500).json({ err });
});
}
You need to specify the sourceKey property in the association - if ignored it will use table + id Reference
The name of the attribute to use as the key for the association in the source table. Defaults to the primary key of the source table
See the following complete example:
class Competition extends Sequelize.Model {
}
Competition.init({
id: {
primaryKey: true,
type: Sequelize.INTEGER,
allowNull: false
},
name: {
type: Sequelize.STRING(36)
},
team_competition_id: {
type: Sequelize.INTEGER,
allowNull: false,
}
}, {
sequelize,
modelName: 'competition',
tableName: 'competitions',
timestamps: false
});
class Team_Competition extends Sequelize.Model {
}
Team_Competition.init({
id: {
primaryKey: true,
type: Sequelize.INTEGER,
allowNull: false
},
name: {
type: Sequelize.STRING(36)
},
}, {
sequelize,
modelName: 'team_competition',
tableName: 'team_competitions',
timestamps: false
});
// use sourceKey here - also make sure you specify `cascade` and `hooks` property
Competition.hasOne(Team_Competition, {sourceKey: 'team_competition_id', foreignKey: 'id', onDelete: 'cascade', hooks: true});
// tests
// create the team_competition
const team_competition = await Team_Competition.create({
id: 1,
name: 'Team A'
});
// create the competition
const competition = await Competition.create({
id: 1,
name: 'Comp A',
team_competition_id: team_competition.id
});
// test the join
const competitions = await Competition.findAll({
include: [
{
attributes: ['id', 'name'],
model: Team_Competition,
}
],
raw: true
});
// delete and verify cascade
await competition.destroy();
Will result in the following SQL generated and executed:
Executing (default): INSERT INTO "team_competitions" ("id","name") VALUES ($1,$2) RETURNING *;
Executing (default): INSERT INTO "competitions" ("id","name","team_competition_id") VALUES ($1,$2,$3) RETURNING *;
// query
Executing (default): SELECT "competition"."id", "competition"."name", "competition"."team_competition_id", "team_competition"."id" AS "team_competition.id", "team_competition"."name" AS "team_competition.name" FROM "competitions" AS "competition" LEFT OUTER JOIN "team_competitions" AS "team_competition" ON "competition"."team_competition_id" = "team_competition"."id";
// cascade deletes
Executing (default): DELETE FROM "team_competitions" WHERE "id" = 1
Executing (default): DELETE FROM "competitions" WHERE "id" = 1

How to modify virtual fields from sequelize findAll result?

I have looked everywhere and couldn't find any clear answers for this.
I have a complex findAll() with many inclusions and each with their own virtual fields.
What I want is to modify the virtual fields of the result, however as it is returning the model instance trying to access the virtual fields returns undefined as they are not in the result yet.
I have tried 'raw: true' but this removes all virtual fields and as my data has nested tables which also have their own virtual fields which I need, I cannot do that.
Example models
var Book = sequelize.define('Book', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
title: {
type: DataTypes.STRING
},
author: {
type: DataTypes.STRING
}
//....other columns,
myField: {
type: DataTypes.Virtual,
get() {
return this.getDataValue('title:') + this.getDataValue('author');
})
Getting the data
model.Book.findAll({
limit: 100
})
.then((result) => {
const newBook = result.map(row => {
return {...row, myField: 'setMyOwnValueHere'}
}
return newBook
}
Get model data first : get
model.Book.findAll({
limit: 100
}).then(result => {
const books = result.map(row => {
//this returns all values of the instance,
//also invoking virtual getters
const book = row.get();
book.myField = 'setMyOwnValueHere';
return book;
});
return books;
});

Write sequlize migration to update table onDelete attribute

I'm using sequlize ORM, I have migration file to create associations between tables:
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.addColumn('testSessions', 'patientId', {
type: Sequelize.UUID,
references: {
model: 'patients',
key: 'id',
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL',
});
},
down: async queryInterface => {
await queryInterface.removeColumn('testSessions', 'patientId');
},
};
I want to change onDelete key to 'CASCADE'. Is it possible to write a migration that would change the value of the onDelete attribute?
I don't want to lose the data I have in the table so undoing migration and running is not a solution for me.
Do you know if you can write a migration that will override the onDelete value, how would it look like?
Just write SQL query that removes constraint and then adds constraint using sequelize.query something like below:
var table = 'YOURTABLENAME';
var constraint = 'YOURCONSTRAINTNAME';
var constraintFkey = 'CONSTRAINTFKEY';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.sequelize.query(`alter table "${table}" drop constraint "${constraint}"`)
.then(() => queryInterface.sequelize.query(
`alter table "${table}"
add constraint "${constraint}" foreign key("${constraintFkey}") references "property_service" ("id")
on delete cascade`
));
},
down: (queryInterface, Sequelize) => {
return queryInterface.sequelize.query(`alter table "${tableName}" drop constraint "${constraintName}"`)
.then(() => queryInterface.sequelize.query(
`alter table "${tableName}"\
add constraint "${constraintName}" foreign key("${constraintFkey}") references "patients" ("id")
on delete no action`
));
},
};

Seeding data across Sequelize associations

I am using Sequelize (new to ORM's) and currently have three tables: card and tags, that have a many-to-many relationship that is established with the third table, card_tags. My question is two fold:
How do I seed data across associations?
How do I create new data (i.e. an API function) that establishes new data across associated data bases?
Please see the below for my models and let me know if I'm leaving anything out. Thanks!
cards model:
'use strict';
module.exports = (sequelize, DataTypes) => {
const Card = sequelize.define('card', {
title: {
type: DataTypes.STRING,
allowNull: false
},
link: {
type: DataTypes.STRING,
allowNull: false
}
});
Card.associate = (models) => {
Card.belongsToMany(models.tag, { through: 'card_tag', as: 'tag' });
};
return Card;
};
tags model:
'use strict';
module.exports = (sequelize, DataTypes) => {
const Tag = sequelize.define('tag', {
title: {
type: DataTypes.STRING,
allowNull: false
}
});
Tag.associate = (models) => {
Tag.belongsToMany(models.card, { through: 'card_tag', as: 'card'});
};
return Tag;
};
card_tags model:
'use strict';
module.exports = function(sequelize, DataTypes) {
const CardTag = sequelize.define('card_tag', {
cardId: DataTypes.INTEGER,
tagId: DataTypes.INTEGER
});
return CardTag;
};
The simplest and quickest way to do is to to insert bulk data in each relation.
You can write sequelize queries to bulkInsert keeping in mind that primary key for each foriegn key is created first.
You can use faker npm module to generate random data.

Categories