Sequalize join multiple model giving alias error - javascript

Hello guys I am new to sequalize and I am facing difficulty to join multiple tables.
Sequalize throws error below:
SequelizeEagerLoadingError: customers is associated to estimations using an alias. You've included an alias (createdby_details), but it does not match the alias(es) defined in your association (customer_details).
Here is my Estimation model:
var Customer = require('../models/Customer')
var User = require('../models/User')
var Estimations = connection.sequelize.define('estimations',{
id:{
type: connection.Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
user_id: {
type: connection.Sequelize.INTEGER
},
title: {
type: connection.Sequelize.TEXT
},
customer_id: {
type: connection.Sequelize.INTEGER
},
project_address: {
type: connection.Sequelize.TEXT
},
bid: {
type: connection.Sequelize.TEXT
},
due_date: {
type: connection.Sequelize.DATEONLY
},
total_cost: {
type: connection.Sequelize.INTEGER
},
created_by: {
type: connection.Sequelize.INTEGER
},
is_deleted: {
type: connection.Sequelize.TINYINT
},
created_at: {
type: connection.Sequelize.DATE
},
updated_at: {
type: connection.Sequelize.DATE
}
},{
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at'
});
Estimations.belongsTo(Customer, {
as: 'customer_details',
foreignKey: 'customer_id',
targetKey: 'id'
});
Estimations.belongsTo(User, {
as: 'createdby_details',
foreignKey: 'created_by',
targetKey: 'id'
});
Here is my controller code:
EstimationSchema.findAndCountAll({
include: [
{
attributes: ['org_name'],
model: CustomerSchema,
as: "customer_details"
},
{
attributes: ['first_name'],
model: UserSchema,
as: "createdby_details"
}
],
attributes: columnName,
where: whereobj,
limit: parseInt(req.body.length),
offset: parseInt(req.body.start),
order: [ sort ]
}).then(records => {
response.recordsTotal = records.count;
response.recordsFiltered = records.count
response.data = records.rows
}).catch(err => {
})
I have one another model 'User' which has primary key 'id' and it has to match with my above 'Estimation' model with 'created_by' field and fetch that user data.
What I want to do is to fetch 'Estimation' table data with associated 'Customer' and 'User' table data.
Thanks in advance.

Related

Sequelize with filter and association eager loading

I'm fairly new to using Sequelize and I'm having issues with findAndCountAll while using filters with eager loading. Following are the two models and their definitions.
const Campaign = sequelize.define(
"campaign",
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.BIGINT,
},
name: {
type: Sequelize.STRING(512),
},
advertiser_id: {
type: Sequelize.BIGINT,
},
},
{
timestamps: true,
createdAt: "created_at",
updatedAt: "modified_at",
});
Campaign.associate = function (model) {
Campaign.hasMany(model.performanceData, {
as: "performanceData",
foreignKey: "campaign_id",
constraints: false,
});
};
const PerformanceData = sequelize.define(
"performanceData",
{
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.BIGINT,
},
campaign_id: {
type: Sequelize.BIGINT,
},
clicks: {
type: Sequelize.BIGINT,
},
date: {
type: Sequelize.STRING(20),
},
},
{
tableName: "performance_data",
timestamps: true,
createdAt: "created_at",
updatedAt: "modified_at",
});
One campaign will have multiple performance data records based on date. I want to get all the campaigns by an advertiser (paginated) while eager loading the aggregate of performance data. So the performance data returned should be aggregate of a particular campaign.
Following is the query I'm using but it doesn't return the data:
const campaigns = await Campaign.findAndCountAll({
where: {
advertiser_id: reqObject.advertiser_id,
},
include: {
as: "performanceData",
model: PerformanceData,
attributes: [],
},
attributes: {
include: [
[
db.Sequelize.fn("SUM", db.Sequelize.col("performanceData.clicks")),
"clicks",
],
],
},
group: ["campaign.id"],
offset: reqObject.page,
limit: reqObject.size});
Can anyone please help with this?

Empty Array when use random with Sequelize

I'm working on an API in Node.js with the Sequelize ORM.
I make an API route to retrieve a random question, it works one time out of three but often returns an empty array. I can't find a solution in the documentation to prevent this...
app.get('/:certifName/:levelName/random', async function (req, res) {
return await Certification.findOne(
{
attributes: ['id', 'label'],
include: [{
model: CertificationLevel,
as: "tcl",
required: true,
attributes: ['id', 'label', 'question_number', 'exam_duration'],
include: [{
attributes: ['id', 'label'],
model: CertificationChapter,
as: "tcc",
required: true,
limit: 1,
order: [ [ Sequelize.fn('RANDOM') ] ],
include: [{
model: Question,
as: "tq",
required: true,
include: [{
model: QuestionChoice,
as: "tqc",
required: false,
attributes: ['id', 'label_fr', 'is_answer'],
}],
}],
}],
where: { label: req.params.levelName }
}],
where: { label: req.params.certifName }
})
.then(data => {
if (data) {
res.send(data);
}
else
res.sendStatus(204);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Error retrieving certification details"
});
});
});
The last model :
module.exports =
class CertificationLevel extends Sequelize.Model {
static init(sequelize) {
return super.init(
{
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
label: Sequelize.STRING,
slug: Sequelize.STRING,
description: Sequelize.TEXT,
question_number: Sequelize.INTEGER,
exam_duration: Sequelize.INTEGER,
created_at: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
},
updated_at: Sequelize.DATE,
deleted_at: Sequelize.DATE
},
{
tableName: 't_certifications_levels',
sequelize,
underscored: true,
timestamps: false
},
);
}
static associate(models) {
this.belongsTo(models.Certification, {
onDelete: "CASCADE",
foreignKey: {
allowNull: false,
name: "certification_id"
}
}),
this.hasMany(models.CertificationChapter, { as:'tcc', foreignKey: 'level_id' })
this.hasMany(models.Subscription, { as:'ts',foreignKey: 'level_id' })
}
}
And this is a SQL query generate :
SELECT "Certification".*,
"tcl"."id" AS "tcl.id",
"tcl"."label" AS "tcl.label",
"tcl"."question_number" AS "tcl.question_number",
"tcl"."exam_duration" AS "tcl.exam_duration"
FROM
(SELECT "Certification"."id",
"Certification"."label"
FROM "t_certifications" AS "Certification"
WHERE "Certification"."label" = 'ISTQB'
AND
(SELECT "tcl"."certification_id"
FROM "t_certifications_levels" AS "tcl"
WHERE ("tcl"."label" = 'Fondation'
AND "tcl"."certification_id" = "Certification"."id")
LIMIT 1) IS NOT NULL
LIMIT 1) AS "Certification"
INNER JOIN "t_certifications_levels" AS "tcl" ON "Certification"."id" = "tcl"."certification_id"
AND "tcl"."label" = 'Fondation';
I don't know why I have two executing to my route?
I am a real beginner in back development...
Thank for you help

Limit Depth on Recursive GraphQL Schema Query using graphql-sequelize resolver (Node.js, express-graphql)

I have 2 Models, User and Post. I want to be able to get User information when querying a post, and be able to get all of a User's posts when querying a user.
they have an association as follows:
User.hasMany(Post, {
foreignKey: 'user',
as: 'posts'
});
Post.belongsTo(User, {
foreignKey: 'id',
sourceKey: 'user',
as: 'userObject'
})
Post.addScope('defaultScope', {
include: [{ model: User, as: 'userObject' }],
}, { override: true })
User.addScope('defaultScope', {
include: [{ model: Post, as: 'posts' }],
}, { override: true })
Here are my Models
User.js
module.exports.userType = new GQL.GraphQLObjectType({
name: 'User',
fields: () => {
const { postType } = require('../Post/Post');
return {
id: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'user unique id'
},
ci_username: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
unique: true,
description: 'case INSENSITIVE username of the user'
},
username: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'case SENSITIVE username of the user'
},
password: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'password for the user'
},
first_name: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'first name of user'
},
last_name: {
type: GQL.GraphQLString,
description: 'last name of user (optional)'
},
profile_picture: {
type: GQL.GraphQLString,
description: 'profile picture for the user'
},
posts: {
type: GQL.GraphQLList(postType),
description: 'list of users posts'
}
}
},
})
/** define User model for the database */
module.exports.User = db.define('user', {
id: {
type: Sequelize.UUID,
primaryKey: true,
unique: true,
},
ci_username: {
type: Sequelize.STRING,
unique: true,
},
username: Sequelize.STRING,
password: Sequelize.STRING,
first_name: Sequelize.STRING,
last_name: Sequelize.STRING,
profile_picture: Sequelize.STRING,
}, {
// Tells sequelize not to query the "CreatedAt" or "UpdatedAt" Columns
timestamps: false
})
Post.js
module.exports.postType = new GQL.GraphQLObjectType({
name: 'Post',
fields: () => {
const { userType } = require('../User/User');
return {
id: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'post unique id'
},
name: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'name of the post'
},
user: {
type: userType,
description: 'user object of who created the post'
},
created_at: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'the datetime the post was created',
}
}
},
})
/** define User model for the database */
module.exports.Post = db.define('post', {
id: {
type: DataTypes.UUID,
primaryKey: true,
unique: true,
},
name: DataTypes.STRING,
user: {
type: DataTypes.STRING,
references: {
model: 'users',
key: 'id'
}
},
created_at: {
type: DataTypes.TIME,
defaultValue: DataTypes.NOW
}
}, {
// Tells sequelize not to query the "CreatedAt" or "UpdatedAt" Columns
timestamps: false
})
Here are my Queries:
allUsers.js
const allUsers = {
type: new GQL.GraphQLList(userType),
args: {
username: {
description: 'username of the user',
type: GQL.GraphQLString,
},
// An arg with the key limit will automatically be converted to a limit on the target
limit: {
type: GQL.GraphQLInt,
default: 10
},
// An arg with the key order will automatically be converted to a order on the target
order: {
type: GQL.GraphQLString
}
},
// use graphql-sequelize resolver with the User model from database
resolve: resolver(User)
}
allPosts.js
const allPosts = {
type: new GQL.GraphQLList(postType),
args: {
username: {
description: 'username of the user',
type: GQL.GraphQLString,
},
// An arg with the key limit will automatically be converted to a limit on the target
limit: {
type: GQL.GraphQLInt,
default: 10
},
// An arg with the key order will automatically be converted to a order on the target
order: {
type: GQL.GraphQLString
}
},
// use graphql-sequelize resolver with the Post model from database
resolve: resolver(Post)
}
I'm currently getting a Maximum call stack size exceeded. I assume because the resolver in the queries are recursively getting details on posts and users infinitely.
Does anyone know of any way to put a depth limitation on the resolver? Or is it just not possible to have a recursive query like this?
You would have to remove the default scope from the included model as shown here like this:
Post.addScope('defaultScope', {
include: [{ model: User.scope(null), as: 'userObject' }],
}, { override: true })
User.addScope('defaultScope', {
include: [{ model: Post.scope(null), as: 'posts' }],
}, { override: true })
To support additional depth, you'd need to implement resolvers for the fields in question, for example:
function resolve (user) {
if (user.posts) {
return user.posts
}
return user.getPosts()
}

How can I give primary key and foreign key relationship in Sequelize.js + Postgres.js

I am not able to give relationship into to two tables User and Media
User have profile field which should contain Media Id.
Right now I have written these models User and Media now I want to fetch data using join query.
USER MODEL
const User = sequelize.sequelize.define('users', {
id: {
type: sequelize.Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
firstName: {
type: sequelize.Sequelize.STRING
},
lastName: {
type: sequelize.Sequelize.STRING
},
email: {
type: sequelize.Sequelize.STRING
},
media_id: {
type: sequelize.Sequelize.INTEGER,
foreignKey: true
}
});
Media.belongsTo(User, {
as: 'media',
foreignKey: {
name: 'media_id',
allowNull: false
}
});
User.find({where: {}, include: [Media]})
User.sync();
MEDIA MODEL
const Media = sequelize.sequelize.define('media', {
id: {
type: sequelize.Sequelize.INTEGER,
primaryKey: true
},
path: {
type: sequelize.Sequelize.STRING
},
type: {
type: sequelize.Sequelize.STRING
}
});
Media.sync();
Firstly, Media.belongsTo(User...) will add a field media_id to your Media model, which is not what you want. Try instead:
User.belongsTo(Media, {
as: 'media',
foreignKey: {
name: 'media_id',
allowNull: false
}
});
Then, you should modify your query:
// Find all users with media where media.id === user.media_id
User.findAll({
include: [{
model: Media,
where: { id: Sequelize.col('user.media_id') }
}]
})

Nodejs use JOIN for two tables on sequelize

I'm trying to implementing this mysql command on sequelize, but as far as i'm newbie to use this library i can't implementing that
i want to make this sql command:
SELECT * FROM users
join users_contacts_lists on users_contacts_lists.mobile_number = users.mobile_number
WHERE users_contacts_lists.user_id = 1
My models to create database schema:
'use strict';
var config = require('../config');
var User = config.sequelize.define('users', {
id: {
type: config.Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
password: {
type: config.Sequelize.STRING
},
username: {
type: config.Sequelize.STRING
},
mobileNumber: {
type: config.Sequelize.STRING,
field: 'mobile_number'
},
status: {
type: config.Sequelize.STRING
},
}, {freezeTableName: true});
var UsersContactsLists = config.sequelize.define('users_contacts_lists', {
id: {
type: config.Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
userId: {
type: config.Sequelize.INTEGER,
field: 'user_id'
},
mobileNumber: {
type: config.Sequelize.STRING,
field: 'mobile_number', defaultValue: 0
}
}, {freezeTableName: true});
UsersContactsLists.belongsTo(ChannelsTypes, {foreignKey: 'user_id'});
User.hasMany(Channels, {foreignKey: 'id'});
User.sync();
UsersContactsLists.sync();
module.exports =
{
users: User,
usersContactsLists: UsersContactsLists
};
how can i resolve this problem? Thanks in advance
You can define the target key and the foreign key both in a relation like this:
User.belongsTo(UsersContactsLists, {targetKey:'mobileNumber',foreignKey: 'mobileNumber'});
And then you can use this:
User.findAll({
include: [{
model: UsersContactsLists,
where: {
userId: 1
}
}]
})
Fiddled around a bit, does this statement do what you want?
User.findAll({
include: [{
model: UsersContactsLists,
where: {
userId: 1
}
}]

Categories

Resources