Sequelize Querying Many to Many Relationship and Accessing Object - node.js

I have a case where I am querying information from two tables that have a many-to-many relationship with a "through" table. When I make my query it appears that I am querying correctly by not using the "through" table as the table join reference and receiving the outputted records with both table attributes, but I am unable to access the field properties of the joined table. Here is the outputted values.
{"fullNameSlug":"Tester Test","email":"test#test.com","firstName":"Tester","lastName":"Test","teams":[{"teamName":"Sales","member":{"memberId":1,"memberEmail":"test#test.com","organizationId":1,"teamId":1,"userId":1,"created_at":"2016-08-21T21:15:19.000Z","updated_at":"2016-08-21T22:00:32.000Z","organization_id":1,"team_id":1,"user_id":1}}]}
Here is my query and how I am setting the data:
.get(function(req, res){
models.User.find({
where: {
organizationId: organization.organizationId
}, attributes: ['email', 'firstName', 'lastName'],
include: [{
model: models.Team,
attributes: ['teamName']
}]
});
}).then(function(currentUsers){
res.jsonp(currentUsers);
console.log(currentUsers);
});
Here is how I was trying to access the teamName in my view: {{currentUsers.teams.teamName}}, which is not returning a value, but {{currentUsers.email}} returns the right user email.
User Table:
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('user', {
userId: {
type: DataTypes.INTEGER,
field:'user_id',
autoIncrement: true,
primaryKey: true
},
firstName: {
type: DataTypes.STRING,
field: 'first_name'
},
lastName: {
type: DataTypes.STRING,
field: 'last_name'
},
email: {
type: DataTypes.STRING,
isEmail: true,
unique: true,
set: function(val) {
this.setDataValue('email', val.toLowerCase());
}
},
password: DataTypes.STRING,
organizationId: {
type: DataTypes.INTEGER,
field: 'organization_id',
allowNull: true
}
}, {
underscored: true,
freezeTableName: true,
},
classMethods: {
associate: function(db) {
User.belongsToMany(db.Organization, { through: 'member', foreignKey: 'user_id'}),
User.belongsToMany(db.Team, { through: 'member', foreignKey: 'user_id'})
}
});
return User;
}
Team table:
module.exports = function(sequelize, DataTypes) {
var Team = sequelize.define('team', {
teamId: {
type: DataTypes.INTEGER,
field: 'team_id',
autoIncrement: true,
primaryKey: true,
notNull: true
},
teamName: {
type: DataTypes.STRING,
field: 'team_name'
},
organizationId: {
type: DataTypes.INTEGER,
field: 'organization_id'
},
},{
underscored: true,
freezeTableName: true,
classMethods: {
associate: function(db) {
Team.belongsToMany(db.User, { through: 'member', foreignKey: 'team_id' });
},
}
});
return Team;
}
Member Table:
module.exports = function(sequelize, DataTypes) {
var Member = sequelize.define('member', {
memberId: {
type: DataTypes.INTEGER,
field: 'member_id',
autoIncrement: true,
primaryKey: true
},
memberEmail: {
type: DataTypes.STRING,
field: 'member_email',
isEmail: true,
unique: true
},
organizationId: {
type: DataTypes.INTEGER,
field: 'organization_id',
allowNull: true
},
teamId: {
type: DataTypes.INTEGER,
field: 'team_id',
allowNull: true
},
userId: {
type: DataTypes.INTEGER,
field: 'user_id',
allowNull: true
}
},{
underscored: true,
freezeTableName: true,
});
return Member;
}
Outputted SQL:
SELECT `user`.*, `teams`.`team_id` AS `teams.teamId`, `teams`.`team_name` AS `teams.teamName`, `teams.member`.`member_id` AS `teams.member.memberId`, `teams.member`.`member_email` AS `teams.member.memberEmail`, `teams.member`.`organization_id` AS `teams.member.organizationId`, `teams.member`.`team_id` AS `teams.member.teamId`, `teams.member`.`user_id` AS `teams.member.userId`, `teams.member`.`created_at` AS `teams.member.created_at`, `teams.member`.`updated_at` AS `teams.member.updated_at`, `teams.member`.`organization_id` AS `teams.member.organization_id`, `teams.member`.`team_id` AS `teams.member.team_id`, `teams.member`.`user_id` AS `teams.member.user_id` FROM (SELECT `user`.`user_id` AS `userId`, `user`.`email`, `user`.`first_name` AS `firstName`, `user`.`last_name` AS `lastName` FROM `user` AS `user` WHERE `user`.`organization_id` = 1 LIMIT 1) AS `user` LEFT OUTER JOIN (`member` AS `teams.member` INNER JOIN `team` AS `teams` ON `teams`.`team_id` = `teams.member`.`team_id`) ON `user`.`userId` = `teams.member`.`user_id`;

Consider your relations, User has many Teams trough table Member and your query returns user with many teams(array of team objects) as expected. You should use user.teams[0].teamName to get specific team by key, or loop objects in this array

Related

Query in join-table for N:M associations in Node JS and Sequelize

I have a classical many-to-many relationship for users which own assets: assets can be transfered to other users during their life so a window time is recorded in the AssetUser "through table",
adding STARTDATE and ENDDATE attributes.
User Table
const User = sequelize.define('User', {
ID: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true
},
FIRSTNAME: {
type: DataTypes.STRING,
allowNull: false
},
LASTNAME: {
type: DataTypes.STRING,
allowNull: false
}},{ timestamps: false }});
Asset Table
const Asset = sequelize.define('Asset', {
ID: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true
},
DESCRIPTION: {
type: DataTypes.STRING,
allowNull: false
}},{ timestamps: false }});
AssetUser Join Table
const AssetUser = sequelize.define('AssetUser', {
id: {
type: DataTypes.INTEGER.UNSIGNED,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
UserID: {
type: DataTypes.INTEGER.UNSIGNED,
references: {
model: User,
key: 'ID'
}
},
AssetID: {
type: DataTypes.INTEGER.UNSIGNED,
references: {
model: Asset,
key: 'ID'
}
},
STARTDATE: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
ENDDATE: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null
}},{ timestamps: false });
The models are created here:
User.belongsToMany(Asset, { through: { model: AssetUser, unique: false }, uniqueKey: 'id' });
Asset.belongsToMany(User, { through: { model: AssetUser, unique: false }, uniqueKey: 'id' });
My problem is that I want to query and find all the results where one asset, owned by one user, during a restricted period. I am not able to query the join-table but only User and Assets tables.
How can I add a "where" condition for the AssetUser table inside my query? How should I insert a STARTDATE and/or ENDDATE condition below?
Asset.findAll({
where: {
DESCRIPTION: 'Personal computer'
},
include: {
model: User,
where: {
FIRSTNAME: 'Marcello'
}
}});
Thanks for your help.
I found the solution
Asset.findAll({ where: { DESCRIPTION: 'Personal computer' }, include: { model: User, through: { where: { FIRSTNAME: 'Marcello' } } }});

How to access the data from mapping table in graphql using sequelize

i am new to sequelize, i have a user table , address table and address type table as given below.
A user can have 2 a different address , permanent and current address, and the type of address (permanent or current ) is specified in the table address type.
I have tried to access the data from mapping table (address_type) in the resolver based on schema and set hasMany relation from user -> address table , but graphql shows association not found error.
How can we get the relation properly in order to get the mapping address type name.
type User{
id:Int
name:String
}
type Address {
id: ID!
user_id:Int
city: String
addr_type:AddressType
}
type AddressType{
id : Int
name:String (permanent|current)
}
table definition
module.exports = function(sequelize, DataTypes) {
return sequelize.define('user', {
id: {
type: DataTypes.INTEGER, allowNull: false, primaryKey: true, autoIncrement: true
},
name: {
type: DataTypes.INTEGER, allowNull: false,
},
}, {
tableName: 'user',
timestamps: false
});
};
module.exports = function(sequelize, DataTypes) {
return sequelize.define('address', {
id: {
type: DataTypes.INTEGER, allowNull: false, primaryKey: true, autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER, allowNull: false, field:"addr_type"
},
addr_type: {
type: DataTypes.INTEGER, allowNull: false, field:"addr_type"
},
city: {
type: DataTypes.STRING, allowNull: false,
},
}, {
tableName: 'address',
timestamps: false
});
};
module.exports = function(sequelize, DataTypes) {
return sequelize.define('address_types', {
id: {
type: DataTypes.INTEGER, allowNull: false, primaryKey: true, autoIncrement: true
},
name: {
type: DataTypes.STRING, allowNull: false,
},
}, {
tableName: 'address_type',
timestamps: false
});
};
relationship
db.user.hasMany(db.address,{foreignKey: 'user_id'});
db.address.belongsTo(db.user,{foreignKey: 'user_id'});
db.address.belongsTo(db.address_types,{foreignKey: 'addr_type'});
resolver code
userts: async (obj, args, context, info ) => User.findAll( {
where: { user_status: 1 },
,
raw: true,
nest: true,
} ).then(userts => {
const response = userts.map(usert => {
return{
// i have 15 fields for a user, if i can access the schema of the corresponsing resolver i can dynamically build the response out put
id: usert.id,
firstName: usert.firstName,
lastName: usert.lastName,
middleName: usert.middleName,
}
})
return response;
}),
You should turn off the option raw in order to get associated objects and use the include option to indicate what associated models you wish to load.
User.findAll( {
where: { user_status: 1 },
include: [{
model: Address,
include: AddressType
}],
raw: false,
nest: true,
}

sequelize self association error Aliased associations must have unique aliases

I'm using sequelize 4.32 and I was trying to write a self-association in one of the tables, I'm not sure if there is something else that I need to do to solve this relation, my goal is to get all the records in my table and include all the records associated with each one
this is the error that I'm getting in the console:
You have used the alias adjucent_stands in two separate associations. Aliased associations must have unique aliases
below you'll find my model:
module.exports = (sequelize, DataTypes) => {
const stands = sequelize.define('stands', {
id: {
type: DataTypes.INTEGER,
unique: true,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
name: {
type: DataTypes.STRING,
field: 'name',
unique: {
args: true,
msg: 'Name already exists ',
},
},
location: {
type: DataTypes.JSON,
field: 'location',
},
remote: {
type: DataTypes.BOOLEAN,
field: 'remote',
defaultValue: false,
},
created_at: {
type: DataTypes.DATE(3),
defaultValue: sequelize.literal('CURRENT_TIMESTAMP(3)'),
},
updated_at: {
type: DataTypes.DATE(3),
defaultValue: sequelize.literal('CURRENT_TIMESTAMP(3)'),
},
}, { freezeTableName: true, timestamps: true, underscored: true });
stands.associate = (models) => {
stands.hasMany(stands, { as: 'adjucent_stands' });
};
return stands;
};

sequelize - inner join gives an error after added a foreign key

i have these 2 models:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('services_prices', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true
},
service_id: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'services',
key: 'id'
}
},
created_at: {
type: DataTypes.DATE,
allowNull: false
},
limit: {
type: DataTypes.INTEGER(11),
allowNull: true
},
price: {
type: DataTypes.INTEGER(11),
allowNull: true
}
});
};
which is parent of this model: (services_user_prices can override services_prices )
module.exports = function(sequelize, DataTypes) {
return sequelize.define('services_user_prices', {
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER(11),
allowNull: true
},
created_at: {
type: DataTypes.DATE,
allowNull: false
},
currency: {
type: DataTypes.STRING(255),
allowNull: true
},
is_active: {
type: DataTypes.INTEGER(1),
allowNull: true,
defaultValue: '0'
},
is_trial: {
type: DataTypes.INTEGER(1),
allowNull: true,
defaultValue: '0'
},
start_date: {
type: DataTypes.DATE,
allowNull: false
},
end_date: {
type: DataTypes.DATE,
allowNull: true
},
price: {
type: DataTypes.INTEGER(11),
allowNull: true
},
bundle_price_id: {
type: DataTypes.INTEGER(11),
allowNull: true,
references: {
model: 'services_prices',
key: 'id'
}
}
});
};
when trying to join them i get an error:
EagerLoadingError: services_prices is not associated to services_user_prices!
const result= await db.services_user_prices.findOne({
where: { is_active: 1, user_id: 123 }, include:[{db.services_prices}]
});
in the db services_user_prices has foreign key to services_prices table
what am i doing wrong?
Well if you are using sequelize then you need to update your model because
by default, sequelize will be looking for foreign key starts with model name like
you have defined bundle_price_id as a foreign key for services_prices.
You need to change your column name to services_price_id then it will get fixed.
or if you want to use bundle_price_id you need to define it in your model relation as.
Model.belongsTo(models.ModelName, { foreignKey: 'your_key'} )
Please feel free if you need to ask anything else.
As complement of the above answer you need to add an identifier with as: on the association like this:
Model.belongsTo(models.ModelName, { foreignKey: 'your_key', as:'your_identifier' } )
Then when you do the include on the method you also call the identifier:
await db.services_user_prices.findOne({
where: { is_active: 1, user_id: 123 },
include:[{
model: db.services_prices
as: 'your_identifier'
}]
});
If you don't define the foreignKey field, the as field will set the column name.

Sequelize duplicate key value violates unique constraint

I am working on nodeJs, and postgresql.
I am facing with an error
duplicate key value violates unique constraint \"AuthoriseDates_pkey\"
Key (id)=(371) already exists.
I set the column id is autoIncrement: true, don't understand why this happens
the max id of columns is 647 but now I cannot insert a record in this table.
here is migrate code :
module.exports = {
up(queryInterface, Sequelize) {
return queryInterface.createTable('AuthoriseDates', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
userId: {
type: Sequelize.INTEGER,
references: { model: 'Users', key: 'id' },
},
lastAuthorise: {
type: Sequelize.DATE,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.fn('NOW'),
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.fn('NOW'),
},
});
},
down(queryInterface) {
return queryInterface.dropTable('AuthoriseDates');
},
};
here is models:
module.exports = (sequelize, DataTypes) => {
const authoriseDate = sequelize.define('AuthoriseDate', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
userId: DataTypes.INTEGER,
lastAuthorise: DataTypes.DATE,
});
authoriseDate.associate = (models) => {
// associations can be defined here
authoriseDate.belongsTo(models.User, { foreignKey: 'userId', });
};
return authoriseDate;
};
here is code insert:
models.AuthoriseDate.create({
userId: userId,
lastAuthorise: new Date().toISOString(),
}).then((create) => {}).catch((error) => {
loggerServer.err('error ', error);
loggerServer.log('debug', { error: error });
return res.status(500).json(result);
});

Resources