Nodejs use JOIN for two tables on sequelize - javascript

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
}
}]

Related

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()
}

Sequalize join multiple model giving alias error

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.

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') }
}]
})

Select specific attributes from table in SequelizeJS

Those are my tables (not all columns included) and relationships
var client = schema.define('client', {
name: {
type: Sequelize.STRING,
allowNull: false
},
}
var task = schema.define('task', {
name: {
type: Sequelize.STRING,
unique: true,
allowNull: false
},
description: {
type: Sequelize.STRING,
}
}
var clientTask = schema.define('clientTask', {
value: {
type: Sequelize.STRING,
allowNull: false,
defaultValue: false
},
}
client.belongsToMany(task, { through: clientTask });
task.belongsToMany(client, { through: clientTask });
I want to get only name from task and value from clientTask, I searching by client id and here is what I tried so far.
client.findAll({
attributes: [],
where: {id: clientId},
include: [{
model: task,
attributes: ['name']
}]
}).then(function (clients) {
//client.tasks is array with task objects(models) with only name attribute
//client.tasks[0].clientTask is object(models) with all attributes but I want only `value`
}
Basically what I want is this query
Select
tasks.name,
clienttasks.value
From
clients Inner Join
clienttasks
On clienttasks.clientId = clients.id Inner Join
tasks
On clienttasks.taskId = tasks.id
Where clients.id = ?
You could query it like this
clients.findById(1, {
attributes: ['id'],
include: [{
model: tasks,
attributes: ['name'],
required: false
}]
}).then(function(client) {
return client.tasks.map(function(task) {
return {
name: task.name,
value: task.clients_tasks.value
};
});
}).then(function(result) {
console.log(result);
// The rest of you logic here...
});

id: null when creating a new item in sequelize

When I try to create a new Conversation item Sequelize will return an object with id: null eventhough there is an valid id in the database. How can I get Sequelize to return the last inserted id to the newly created item?
Conversation.create({
type: 'private',
createdBy: 1,
}).then(conversation => {
reply(conversation);
});
Will return
{
"type": "conversations",
"id": null,
"createdBy": 1,
"created_at": "2016-03-18T01:47:48.000Z"
}
My code:
const Conversation = model.define('Conversation', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
},
type: {
type: Sequelize.ENUM,
values: ['private', 'group'],
validate: {
isIn: ['private', 'group'],
},
},
createdBy: {
type: Sequelize.INTEGER,
field: 'created_by',
},
}, {
tableName: 'conversations',
timestamps: true,
createdAt: 'created_at',
updatedAt: false,
getterMethods: {
type: () => 'conversations',
},
});
const User = model.define('User', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
},
firstName: {
type: Sequelize.STRING,
field: 'first_name',
allowNull: false,
},
lastName: {
type: Sequelize.STRING,
field: 'last_name',
allowNull: true,
},
email: {
type: Sequelize.STRING,
allowNull: false,
},
profileImg: {
type: Sequelize.STRING,
field: 'profile_img',
allowNull: false,
},
password: Sequelize.STRING,
}, {
tableName: 'users',
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
getterMethods: {
type: () => 'users',
},
});
Conversation.belongsToMany(User, {
foreignKey: 'conversation_id',
otherKey: 'user_id',
through: 'conversation_user',
timestamps: false,
});
User.belongsToMany(Conversation, {
as: 'conversations',
foreignKey: 'user_id',
otherKey: 'conversation_id',
through: 'conversation_user',
timestamps: false,
});
Yo need to put autoIncrement: true in id field:
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
}
Personally I would advice to skip the id column as sequalize does it automatically for you and works nicely.
hope it helps :)
Problem was my MySQL version (5.6 instead of 5.7), updated it and now I'm getting id's of the created items in the promise.
I'm not sure about how Sequelize is working with id field, I get null if I do instance.id, bug I can get the real value at DB if I do the following:
console.info(instance.id); // null
console.info(instance.get('id')); // 25 => Real ID
console.info(instance.getDataValue('id')); // 25 => Real ID
Something similar is happening with other fields like createdAt and updatedAt.
In order to get the real value at id field and other related fields, I added following logic to Model declaration:
class FooModel extends Model {
// ...
/**
* #inheritdoc
*/
public async save(options?: SaveOptions<TModelAttributes>): Promise<this> {
await super.save(options);
this.loadBaseData();
return this;
}
/**
* #inheritdoc
*/
public async reload(options?: FindOptions<TModelAttributes>): Promise<this> {
await super.reload(options);
this.loadBaseData();
return this;
}
private loadBaseData() {
this.id = this.getDataValue('id');
this.createdAt = this.getDataValue('createdAt');
this.updatedAt = this.getDataValue('updatedAt');
}
}
because if you only build without save it then:
instance.id // null
so you need:
instance.save()
instance.id // someNumber

Categories

Resources