SQL JOIN with condition on second table with sequelizejs - mysql

I have the following models:
const User = sequelize.define('user', {
name: Sequelize.TEXT,
avatar: Sequelize.TEXT,
});
const Event = sequelize.define('event', {
title: Sequelize.STRING,
description: Sequelize.TEXT,
timestamp: Sequelize.DATE,
});
const EventUser = sequelize.define('event_user', {});
Event.hasMany(EventUser);
EventUser.belongsTo(User);
So EventUser holds my list of participants for a specific event.
I'm trying to query for all events where user X is participating:
let events = await Event.findAll({
include: [
{model: EventUser, include: [{model: User, where: {id: 1}}]}
],
});
But it won't fetch the list of other participants for that event. Not sure how to achieve that, thanks!

Right way is to define many-to-many relation between Users and Events
User.belongsToMany(Event, {through: 'EventUser'});
Event.belongsToMany(User, {through: 'EventUser'});
Then, you can get all events of some user like this:
User.findById(userId).then(function(user){
return user.getEvents();
}).then(function(events){
//here's events
});
Or through one query:
Event.findAll({
include: [{
model: User,
where: {id: userId}
}]
}).then(function(events){
//here's events
});

Related

hasOne association in sequelize making multiple copies

So I am working on a project with Users, Products Carts, etc. And I am using sequelize to maintain a one-to-one relation between my User and the cart associated with it. I only want one Cart to be there for one User
User.hasOne(Cart);
Cart.belongsTo(Product);
sequelize.sync().then(
result=>{
return User.findByPk(1)
}
).then(user=>{
if(!user){
return User.create({
name: "Ary",
email: "test#test.com",
})
}
return user;
}).then(user=>{
console.log("here");
return user.createCart();
}).then(cart=>{
console.log("cartmain:");
console.log(cart);
app.listen(3000);
})
.catch(err => {console.log(err);})
I am currently working with only 1 default user, and by using the code above I am ensuring that the user is available and when it is confirmed I create a basket for that user using user.createCart() .
But whenever I run my code a new cart for that user gets created whereas I dont want that and dont expect that to happen as I am using one-to-one relation
Below are the models for my User and Cart:
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const User = sequelize.define('user', {
id:{
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
allowNull: false,
},
email:{
type: Sequelize.STRING,
allowNull: false
}
})
module.exports = User;
const Sequelize = require('sequelize');
const sequelize = require("../util/database");
const Cart = sequelize.define('cart', {
id:{
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
}
})
module.exports = Cart
What can be done so that if a cart is not associated with a User it gets created if one is then it doesn't using sequelize

Sequelize in Nodejs creating duplicate tables upon app start

Ok. Landscape: Node, MySql, Sequelize
Issue: After creating a new data model & migration (node migrate.js which creates just fine), upon app start Sequelize creates a duplicate Table (and also forwards form data to the new table).
Ex: db.virtual_class is the main table, and upon start, db.virtual_classes is also created.
My model:
const Sequelize = require('sequelize');
const sequelize = require('../sequelize');
const model = sequelize.define('virtual_class', {
id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true },
style: Sequelize.STRING, // e.g. Style of class
description: Sequelize.STRING(1024), // e.g. class Details
jwt_secret: Sequelize.STRING, // e.g. rando string to be used to gen unique keys for every room
});
module.exports = model;
I've isolated what I think is the issue - I'm including the model in a variable on my index controller for my functions.
const Virtual_class = require('./model');
const classQuery = require('./classQuery');
async function addClass({ style, description, secret }) {
const vClass = await Virtual_class.create({
style,
description,
jwt_secret: secret,
}, { raw: true });
return classQuery(vClass);
}
module.exports = {
addClass,
};
Class Query function to return the data in a usable object:
function classQuery(queryResult) {
if (!queryResult) {
return null;
}
return {
id: queryResult.id,
style: queryResult.style,
description: queryResult.description,
secret: queryResult.jwt_secret,
};
}
module.exports = classQuery;
and the migration:
module.exports = {
up: (sequelize, Sequelize) => sequelize.getQueryInterface().createTable('virtual_class', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
style: {
type: Sequelize.STRING,
},
description: {
type: Sequelize.STRING,
},
jwt_secret: {
type: Sequelize.STRING,
},
createdAt: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.fn('now'),
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.fn('now'),
},
}),
down: sequelize => sequelize.getQueryInterface().dropTable('virtual_class'),
};
Net result is fine before I run app - DB shows new table, After running app - DB shows dup table.
I'm a relative noob, and been wracking my brain (and trying to find solutions here) to the problem. I've done this before with other migrations with no issue.
Any advice is appreciated! Thanks!
DOH! For those who are new like me - Sequelize automatically creates plural tables by default, You can force the override tp singular table names.

Association without foreign keys and make join in table

I am working on Node + sequelize + mysql. All the things is working fine in my code. Now i need to add search field in list page. In this search page there is showing user first name, last name, company name and status. I got all data from one table but company comes from "Company" table. In user table there is company_id. I can not make association for company_id. Now i want to search from company_name too. How i add include without association.
const { User, Company } = require("../models");
if(query.trim() != "") {
[err, users] = await to(User.findAll({
where : {[Op.or] : {first_name:{ [Op.like]: '%'+query.trim()+'%' },last_name:{ [Op.like]: '%'+query.trim()+'%' }}},
include : [
{
model:Company,
where : {company_name:{ [Op.like]: '%'+query.trim()+'%' }}
}],
limit: 5,
offset: 0,
order: [[id, ASC]]
}));
console.log('err ----------------',err);
console.log(users);
}
I got below error on from above code :
err ---------------- { filename:
'/var/www/html/fullproject-name/backend/node_modules/sequelize/lib/model.js',
line: 583,
row: 13,
message: 'Company is not associated to User!',
type: 'SequelizeEagerLoadingError',
stack:
'SequelizeEagerLoadingError: Company is not associated to User!\n at Function._getIncludedAssociation..... }
User Model Code :
module.exports = (sequelize, DataTypes) => {
var Model = sequelize.define('User', {
email: {type: DataTypes.STRING, allowNull: true, unique: true, validate: { isEmail: {msg: "Phone number invalid."} }},
company_id: DataTypes.INTEGER,
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
active:DataTypes.INTEGER,
});
}
Company Model Code :
module.exports = (sequelize, DataTypes) => {
var Model = sequelize.define('Company', {
company_name: DataTypes.STRING,
company_attachment: DataTypes.STRING,
});
}
You need to associate your models with each other in order to be able to query them together with joins. In the below sample, I added some associations for User and Company. The relation I defined (which you can change) is one to many. A user belongs to one company; a company has many users.
This association will put a foreign key of company_id on the User model.
const models = require("./models.js") // Update if necessary
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define("User", { // Changed from Model to User
email: {
type: DataTypes.STRING,
allowNull: true,
unique: true,
validate: { isEmail: { msg: "Phone number invalid." } }
},
company_id: DataTypes.INTEGER,
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
active: DataTypes.INTEGER
});
User.belongsTo(models.Company); // User to Company association
};
const models = require("./models.js") // Update if necessary
module.exports = (sequelize, DataTypes) => {
var Company = sequelize.define("Company", { // Changed from Model to Company
company_name: DataTypes.STRING,
company_attachment: DataTypes.STRING
});
Company.hasMany(models.User); // Company to User association
};

Unique email address with Sequelize

I'm running ExpressJS with Sequelize/MySQL and trying very hard to get a simple validator check working for unique email address.
Here is my user model. And for the life of me I don't understand why this is allowing records that have duplicate email address. Surely the email.unique=true would be preventing this.
'use strict';
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define('User', {
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: {
msg: "Must be a valid email address",
}
}
}
}, {
indexes: [{
fields: ['email'],
unique: true,
}]
});
return User;
};
Any help appreciated.
EDIT:
As requested here is the controller code for create user.
const User = require('../models').User;
exports.create = (req, res) => {
User.create( req.body )
.then( user => {
res.json( user );
})
.catch( errors => {
res.json({ errors: errors.errors });
});
};
One way to solve this is by using sequelize.sync() to create your table according to the schema specified in the model if the table exists then you should pass {force: true} to the sync method, the table will be dropped and a new one will be created.
though using sequelize.sync() is not highly recommended especially in production due to issues with migration files etc, you can google than for more details.

How to fetch all fields of table using sequelize in nodejs?

I want to fetch all fields without to write all fields name of table. How to use * to fetch all the fields from the table ?
This is UserController function to fetch all the rows with all fields of table.
user.findAll({
attributes: ['name','email','mobile','dob','address','image','is_active'],
where:{
is_active:'1',
name:{$like:'%%'}
},
limit:10
}).then(function(users,fields){
console.log(users);
res.send({error:false,message:'users list',data:users});
}).catch(function(err){
console.log('Oops! something went wrong, : ', err);
});
This is model code and define some property of model.
var sequalize = require('../../config/db_config');
const User = sequalize.define('user',{},{
timestamps: false,
paranoid: true,
underscored: true,
freezeTableName: true,
tableName: 'user',
createdAt:'created_on',
updatedAt:'updated_on'
});
User.sync({force:false}).then(() => {
console.log('Table is created!');
}).catch(err => {
console.log('An error occur when table is created!');
});
module.exports = User;
Please help me that how to fetch all fields with write to attribute in controller.
Simply ommit the attributes key in your query and all the fields will return.
user.findAll({
where:{
is_active:'1',
name:{$like:'%%'}
},
limit:10
}).then(function(users){
console.log(users);
res.send({error:false,message:'users list',data:users});
}).catch(function(err){
console.log('Oops! something went wrong, : ', err);
});
EDIT: In your model definition is best if you specify the fields your table has. Like so: http://docs.sequelizejs.com/manual/tutorial/models-definition.html
Otherwise you will have to specify the attributes key in every find operation.
#yBrodsky is right . Also you should make model like this.so that it can know the field to select when no attribute.
const User = sequalize.define('user',{},{
timestamps: false,
paranoid: true,
underscored: true,
freezeTableName: true,
tableName: 'user',
createdAt:'created_on',
updatedAt:'updated_on'
});
to this
var sequalize = require('../../config/db_config');
const User = sequalize.define('user',{
name: {type: Sequelize.STRING},
email: {type: Sequelize.STRING},
mobile: {type: Sequelize.INTEGER},
dob: {type: Sequelize.DATE}
address: {type: Sequelize.STRING},
image: {type: Sequelize.INTEGER},
is_active: {type: Sequelize.BOOLEAN }
},{
timestamps: false,
paranoid: true,
underscored: true,
freezeTableName: true,
tableName: 'user',
createdAt:'created_on',
updatedAt:'updated_on'
});
for dtatype see here
http://docs.sequelizejs.com/manual/tutorial/models-definition.html#data-types
Simply remove attributes from model , you will be able fetch all columns