Been looking at various answers and git issues and still can't get it to work. I have drivers model and CarDrivers model. A driver can drive multiple cars so I want to create a one-to-many relationships.
Drivers Model is (models/drivers.js):
'use strict';
module.exports = (sequelize, DataTypes) => {
const Driver = sequelize.define('Driver', {
name: DataTypes.STRING
}, {});
Driver.associate = function(models) {
// associations can be defined here
};
return Driver;
};
now CarDrivers (models/cardrivers.js):
'use strict';
module.exports = (sequelize, DataTypes) => {
const CarDriver = sequelize.define('CarDriver', {
status: DataTypes.INTEGER,
}, {});
CarDriver.associate = function(models) {
// associations can be defined here
CarDriver.belongsTo(models.Driver, {
onDelete: "CASCADE",
foreignKey: 'id',
as: 'car_driver'
});
};
return CarDriver;
};
Data migration works with no errors but I don't see an entry/related column in table CarDrivers. Anybody can help fix it please.
The issue with your code is that the foreign_key in your association definition cannot be id, as that will clash with the id of the CarDriver table. If you change it to driver_id, you will see that column in the car_driver table:
const Driver = sequelize.define('driver', {
name: { type: Sequelize.STRING }
});
const CarDriver = sequelize.define('car_driver', {
name: { type: Sequelize.STRING }
});
CarDriver.belongsTo(Driver, {
onDelete: 'CASCADE',
foreignKey: 'driver_id'
});
const driver = await Driver.create({
name: 'first driver'
})
const carDriver = await CarDriver.create({
name: 'first carDriver',
driver_id: driver.id
})
Two notes:
foreignKey is optional. If you leave it blank, Sequelize will default to camelcase, e.g. driverId
Your migration file must account for the foreign key on the CarDriver table:
up: function(queryInterface, Sequelize) {
return queryInterface.createTable('car_driver', {
id: {},
driver_id: {
..
}
});
}
Related
I am building a Node JS web application. I am using Sequelize, https://sequelize.org/ for manipulating the database logic. Now, I am having a problem with bulk insert and many-to-many relationships.
I have a model called, Region with the following code.
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Region extends Model {
static associate(models) {
// define association here
Region.belongsToMany(models.ExchangeRequest, {
through: 'RegionExchangeRequests',
as: 'exchangeRequests',
foreignKey: "region_id",
otherKey: "exchange_request_id"
})
}
};
Region.init({
name: DataTypes.STRING,
latitude: DataTypes.FLOAT,
longitude: DataTypes.FLOAT
}, {
sequelize,
modelName: 'Region',
});
return Region;
};
Then, I have a model called, ExchangeRequest with the following code.
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class ExchangeRequest extends Model {
static associate(models) {
// define association here
ExchangeRequest.belongsToMany(models.Region, {
through: 'RegionExchangeRequests',
as: 'regions',
foreignKey: 'exchange_request_id',
otherKey: "region_id"
})
ExchangeRequest.belongsTo(models.User, { foreignKey: 'userId', as: 'user', onDelete: 'cascade' });
}
};
ExchangeRequest.init({
exchange_rate: DataTypes.DECIMAL,
currency: DataTypes.STRING,
amount: DataTypes.DECIMAL,
buy_or_sell: DataTypes.INTEGER,
note: DataTypes.STRING,
email: DataTypes.STRING,
phone: DataTypes.STRING,
address: DataTypes.STRING,
userId: DataTypes.INTEGER
}, {
sequelize,
modelName: 'ExchangeRequest',
});
return ExchangeRequest;
};
Then I have the RegionExchangeRequest with the following code.
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class RegionExchangeRequest extends Model {
static associate(models) {
// define association here
}
};
RegionExchangeRequest.init({
region_id: DataTypes.INTEGER,
exchange_request_id: DataTypes.INTEGER
}, {
sequelize,
modelName: 'RegionExchangeRequest',
});
return RegionExchangeRequest;
};
I have a function that is doing the bulk insert on RegionExchangeReques as follow.
const create = async ({
exchange_rate,
currency,
amount,
buy_or_sell,
note,
email,
phone,
address,
region_ids,
userId
}) => {
try {
let exchangeRequest = await ExchangeRequest.create({
exchange_rate,
currency,
amount,
buy_or_sell,
note,
email,
phone,
address,
userId
});
if (region_ids && region_ids.length > 0) {
let pivotData = [ ];
region_ids.forEach(regionId => {
pivotData.push({
exchange_request_id: exchangeRequest.id,
region_id: regionId
})
})
let regionExchangeRequests = await RegionExchangeRequest.bulkCreate(pivotData);
}
return {
error: false,
data: exchangeRequest
}
} catch (e) {
return {
error: true,
code: 500,
message: e.message
}
}
}
When the function is called, it is throwing the following error.
"column \"id\" of relation \"RegionExchangeRequests\" does not exist"
The following line is throwing the error.
let regionExchangeRequests = await RegionExchangeRequest.bulkCreate(pivotData);
What is wrong with my code and how can I fix it?
In many-to-many relationship you specified RegionExchangeRequests as through table that connects two other tables, and in sequelize you cannot call usual model methods in through table.To do so you need to create super many-to-many relationship, for more information check out this link advanced-associations-in-sequelize
I currently have a User model and a Team model that I want to associate.
User.js Model
"use strict";
module.exports = sequelize => {
const User = sequelize.define(
"User",
{
id: {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV1,
primaryKey: true,
allowNull: false
},
...more fields
}
{ tableName: "Users", timestamps: true }
);
User.associate = function(models) {
// 1 to many with skill
User.hasMany(models.Skill, {
foreignKey: "userId"
});
// 1 to many with team
User.hasMany(models.Team, {
foreignKey: "userId"
});
};
return User;
};
Team.js Model
"use strict";
module.exports = (sequelize, DataTypes) => {
const Team = sequelize.define(
"Team",
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
...more fields
},
{ tableName: "Teams", timestamps: true }
);
Team.associate = function(models) {
Team.belongsTo(models.User, {
foreignKey: "userId"
});
};
return Team;
};
The column userId is automatically added to the team's table with the correct type (uuid) but no matter what I try it's always null.
I have tried just defining without options, and again the column was added, but set to null when a team was created.
1). Define the associations with no options.
User.associate = function(models) {
User.hasMany(models.Team);
}
Also, I have another table "Skills" that uses the same code but it works.
"use strict";
module.exports = (sequelize, DataTypes) => {
const Skill = sequelize.define(
"Skill",
{
id: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
},
{ tableName: "Skills", timestamps: true }
);
Skill.associate = models => {
Skill.belongsTo(models.User, {
foreignKey: "userId"
});
};
return Skill;
};
This is the method i'm using to create the team.
// Create a new team
exports.createTeam = async (req, res) => {
// Get the user id from the session
const userId = req.session.passport.user.id;
const { title } = req.body;
// Make sure the user hasn't already created a team with that title.
const existingTeam = await models.Team.findOne({
where: { title: title, userId: userId }
});
if (existingTeam !== null) {
// Response and let the user know.
...
return;
}
const defaultTeamValues = {
title: title,
...
};
// No existing team was found with that title and created by that user.
// Create it.
const team = await models.Team.create(defaultTeamValues);
// Done
res.status(200).json(team);
};
New record in Team's table showing null value in foreign key (userId) column.
I'm using pgAdmin 4 to view the tables and each table has the correct constraints fkeys too.
I feel like I'm missing something simple here, but I've read the docs and searched for similar issues but haven't found what I needed. What am I missing?
Ok, so I sort of figured out the problem. Instead of using
// Look for existing team
const existingTeam = await models.Team.findOne({
where: { title: title, userId: userId }
});
if (existingTeam !== null) {
...
return;
}
// No existing team was found with that title and created by that user.
// Create it.
const team = await models.Team.create(defaultTeamValues);
I switch to this method.
const team = await models.Team.findOrCreate({
where: {
title: title,
userId: userId
},
// title and userId will be appended to defaults on create.
defaults: defaultTeamValues
});
The difference being that findOrCreate will append, the values in the where query, to the default values you provide.
This is what I did previously when adding new skills and that's why my Skills records had the userId and Teams did not.
So at this point, I don't know if my associations are even working because I'm actually just adding the userId value into the new record.
Back to reading the docs and testing.
I've got two tables that are structured like this:
FeedPost
id, text, likecount, commentcount
Comment
id, text, lkpfeedpostid
So there's a foreign key from comment to feedpost via lkpfeedpostid. So one FeedPost could have many Comment. I'm trying to set this up in sequalize so that when I do a FeedPost.findAll(), it pulls back the feed posts with all the comments.
Here's how I've set it up:
Model Definitions:
FeedPost:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('FeedPost', {
...
...
}, {
tableName: 'FeedPost',
classMethods: {
associate : function(models) {
FeedPost.hasMany( Comment, { as: 'comments' });
},
},
});
};
Comment:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('Comment', {
...
...
}, {
tableName: 'Comment',
classMethods: {
associate : function(models) {
Comment.belongsTo(FeedPost, { foreignKey: 'lkpfeedpostid'})
},
},
});
};
I'm importing them like:
const FeedPost = sequelize.import('../models/FeedPost');
const Comment = sequelize.import('../models/Comment');
And passing them into an express router like:
app.use(feed(FeedPost, Comment));
module.exports = (FeedPost, Comment) => {
const api = Router();
api.get('/api/feed', (req, res) => {
FeedPost.findAll( { include: [ {model: Comment, as: 'Comment' }]}).then(results => {
res.json({results});
});
}
I've tried tons of variations of this found in these links:
http://docs.sequelizejs.com/manual/tutorial/models-definition.html#import
http://docs.sequelizejs.com/class/lib/associations/has-many.js~HasMany.html
https://github.com/sequelize/sequelize/issues/3273
And whenever I hit the route, I keep getting the error that says
Unhandled rejection SequelizeEagerLoadingError: Comment is not associated to Feed!
I am going with that assumption that your sequelize version >=4.
classMethods and instanceMethods have been removed. The changelog can be found here : Sequelize V4 Breaking Changes
From their docs you can refer the current method to specify associations.
FeedPost
module.exports = function(sequelize, DataTypes) {
const FeedPost = sequelize.define('FeedPost', {/*Attributes here*/});
FeedPost.hasMany(Comment, { as: 'comments' })
};
Comment
module.exports = function(sequelize, DataTypes) {
const Comment = sequelize.define('Comment', {/*Attributes here*/});
Comment.BelongsTo(Comment, { foreignKey: 'lkpfeedpostid', targetKey: 'id' })
};
The following query should work:
FeedPost.findAll( { include: [ {model: Comment, as: 'comments' }]})
Looked on the internet about similar questions/errors, none of them helped me...
Unhandled rejection SequelizeEagerLoadingError: Task is not associated to User!
My users route
router.get('', function (req, res) {
models.User.findAll({
include: [
{
model: models.Task,
as: 'tasks'
}
]
}).then(function (users) {
res.send(users);
});
});
User model
'use strict';
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
email: DataTypes.STRING
}, {
underscored: true
});
User.associations = function (models) {
User.hasMany(models.Task, { as: 'tasks' });
};
return User;
};
Task model
'use strict';
module.exports = (sequelize, DataTypes) => {
const Task = sequelize.define('Task', {
name: DataTypes.STRING
}, {
underscored: true
});
Task.associations = function (models) {
Task.belongsTo(models.User);
};
return Task;
};
I associate them both, and made a bidirectional relationship..
As you are using the finder function for association with as option, Sequelize cannot find that alias, as it is not defined explicitly anywhere. Please try this one:
User.associations = function (models) {
User.hasMany(models.Task, { as: 'tasks' });
};
Hope this helps.
I got two models associates by belongsToMany associations.
Posts.js :
'use strict';
module.exports = function(sequelize, DataTypes) {
var Posts = sequelize.define('Posts', {
title: DataTypes.STRING,
body: DataTypes.STRING
}, {
classMethods: {
associate: function(models) {
Posts.belongsToMany(models.Tags, {
through: 'PostsTags',
as:'posts_has_tags',
foreignKey:'postId'
});
}
}
});
return Posts;
};
and Tags.js :
'use strict';
module.exports = function(sequelize, DataTypes) {
var Tags = sequelize.define('Tags', {
name: DataTypes.STRING
},{
classMethods: {
associate: function(models) {
Tags.belongsToMany(models.Posts, {
through: 'PostsTags',
as:'posts_has_tags',
foreignKey:'tagId'
});
}
}
});
return Tags;
};
In my db i got 2 existing tags. (id:1 and id:2)
I got trouble when i create a Post i want to associate it to one of these tags.
By running this code :
create: function(request, reply){
let post = Object.assign({}, request.payload, request.params);
models.Posts.create({
title: post.title,
body: post.body,
posts_has_tags: [{tagId:1}]
},{
include: [{model:models.Tags, as:'posts_has_tags'}]
}).then(function(newPost){
if(!newPost){
return reply('[404] Not found').code(404);
}
reply(newPost).code(200);
})
}
it runs this query :
INSERT INTO `Posts` (`id`,`title`,`body`,`createdAt`,`updatedAt`) VALUES (DEFAULT,'TITLE 1','BODY 1','2017-02-05 18:33:21','2017-02-05 18:33:21');
Executing (default): INSERT INTO `Tags` (`id`,`createdAt`,`updatedAt`) VALUES (DEFAULT,'2017-02-05 18:33:21','2017-02-05 18:33:21');
Executing (default): INSERT INTO `PostsTags` (`createdAt`,`updatedAt`,`postId`,`tagId`) VALUES ('2017-02-05 18:33:21','2017-02-05 18:33:21',70,20);
It creates a new post but also a new Tag that i don't want.
It creates the associations in poststags table but with the bad tag id (the one just created instead of the id 1)
In the promise how can i access to the setAssociation() or addAssocation() method sequelize is supposed to create on belongsToMany associations :
I got errors or undefined if i try newPost.addTags or newPost.setTags, or models.Posts.addTags or models.Posts.setTags
If anybody can help me, he's welcome.
I stuck on this for days and i'd like to understand right how i can use sequelize the best way.
I changed the alias "as" for both models :
Posts.js :
'use strict';
module.exports = function(sequelize, DataTypes) {
var Posts = sequelize.define('Posts', {
title: DataTypes.STRING,
body: DataTypes.STRING
}, {
classMethods: {
associate: function(models) {
Posts.belongsToMany(models.Tags, {
through: 'PostsTags',
as:'postHasTags',
foreignKey:'postId'
});
}
}
});
return Posts;
};
Tags.js :
'use strict';
module.exports = function(sequelize, DataTypes) {
var Tags = sequelize.define('Tags', {
name: DataTypes.STRING
},{
classMethods: {
associate: function(models) {
Tags.belongsToMany(models.Posts, {
through: 'PostsTags',
as:'tagHasPosts',
foreignKey:'tagId'
});
}
}
});
return Tags;
};
Both alias are reversed.
When i create a new post or update one, i can access to the setter built by sequelize (model.setAssociation) in the promise :
upsert: function(request, reply){
let receivedPost = Object.assign({}, request.payload, request.params);
models.Posts.find({
where:{ id:receivedPost.id }
}).then(post => {
if(post){
post.setPostHasTags(receivedPost.tags)
reply(post).code(200)
} else {
models.Posts.create({
title: receivedPost.title,
body: receivedPost.body
}).then(newPost => {
newPost.setPostHasTags(receivedPost.tags)
reply(newPost).code(200);
});
}
});