How to use inner joins in sequilize - mysql

SELECT v.vehicle_id,v.vehicle_model_id,u.user_id,u.first_name FROM user u INNER JOIN user_vehicle v ON u.user_id= v.user_id WHERE u.user_id=3
For the above query i use the following command
userModel.find({ where: {user_id: 3}, include: [userVehicleModel] }).success(function(user){
console.log(user)
})
It gives error:Possibly unhandled Error: user_vehicle is not associated to user!
Thanks in advance.

There's a good answer here.
Simple working solution:
'use strict';
var Sequelize = require('sequelize');
var sequelize = new Sequelize(/*database*/'test', /*username*/'test', /*password*/'test',
{host: 'localhost', dialect: 'postgres'});
var User = sequelize.define('User', {
firstName: {type: Sequelize.STRING},
lastName: {type: Sequelize.STRING}
});
var Vehicle = sequelize.define('Vehicle', {
brand: {type: Sequelize.STRING}
});
var firstUser;
User.hasMany(Vehicle, {constraints: true});
Vehicle.belongsTo(User, {constraints: true});
sequelize.sync({force: true})
.then(function () {
return User.create({firstName: 'Test', lastName: 'Testerson'});
})
.then(function (author1) {
firstUser = author1;
return Vehicle.create({UserId: firstUser.id, brand: 'Ford'});
})
.then(function () {
return Vehicle.create({UserId: firstUser.id, brand: 'Toyota'})
})
.then(function () {
return User.findAll({
where: {id: 1},
include: [Vehicle]
});
})
.then(function displayResults(results) {
results.forEach(function (c) {
console.dir(c.toJSON());
});
})
.then(function () {
process.exit(0);
});

For one to many associations in sequilize and to get record you just need to write this query.
let getuserId = req.query.user_id;
let foundUser await userModel.findOne({
where: {user_id: getuserId },
include: [ { model: userVehicleModel } ] })
});
if (foundUser) console.log(foundUser);

Related

Sequelize N:M ParentModel.setChilds(ChildArray) is not a function (Magic Method?)

In my program, I'd like to update many cateogories has a parent table named Column. Also, a category can contain of many columns.(N:M)
So I tried to update a category to the post, but it failed. Here is the code I've tried
let updateColumn = async function(req, res) {
let column_id = req.body.id;
let column_title = req.body.title;
let column_content_text = req.body.contentText;
let column_content_html = req.body.contentHTML;
let column_categorys = req.body.categoris;
let column_tags = req.body.tags;
let column_thumbnail_url = process.env.CDN_COLUMN_ENDPOINT;
column_thumbnail_url += column_title;
column_thumbnail_url += '/';
column_thumbnail_url += '0.png';
var category_array = [];
var tag_array = [];
await sequelize.transaction(async transaction => {
try {
await Column.update({
column_title: column_title,
column_content_text: column_content_text,
column_content_html: column_content_html,
column_thumbnail_url: column_thumbnail_url,
}, {
where: {
id: column_id,
},
}, {transaction: transaction});
const column = await Column.findOne({
where: {
id: column_id,
},
transaction,
});
for(var i in column_categorys) {
const [category, created] = await Category.findOrCreate({
where : {
category_name: column_categorys[i],
},
transaction,
});
category_array.push(category);
}
for(var j in column_tags) {
const [tag, created] = await Tag.findOrCreate({
where : {
tag_name: column_tags[j],
},
transaction,
});
tag_array.push(tag);
}
await column.setCategorys(
category_array,
{ transaction },
);
await column.setTags(
tag_array,
{ transaction },
);
res.json({
responseCode: 400,
responseMsg: 'Success',
});
} catch (err) {
console.error(err);
res.json({
responseCode: 404,
responseMsg: 'Fail',
});
}
});
}
column_info.js
const Sequelize = require('sequelize');
module.exports = class Column extends Sequelize.Model {
static init(sequelize) {
return super.init({
column_title: {
type: Sequelize.STRING(200),
allowNull: false,
unique: true,
},
column_content_text: {
type: Sequelize.STRING(10000),
allowNull: false,
},
column_content_html: {
type: Sequelize.STRING(10000),
},
column_thumbnail_url: {
type: Sequelize.STRING(300),
},
}, {
sequelize,
timestamps: true,
underscored: true,
modelName: 'Column',
tableName: 'columns',
paranoid: true,
charset: 'utf8',
collate: 'utf8_general_ci',
});
}
static associate(db) {
db.Column.belongsToMany(db.Category, {
through: 'ColumnCategory',
unique: false,
});
db.Column.belongsToMany(db.Tag, {
through: 'ColumnTag',
unique: false,
});
}
};
category_info.js
const Sequelize = require('sequelize');
module.exports = class Category extends Sequelize.Model {
static init(sequelize) {
return super.init({
category_name: {
type: Sequelize.STRING(50),
allowNull: false,
unique: true,
},
}, {
sequelize,
timestamps: false,
underscored: true,
modelName: 'Category',
tableName: 'categorys',
paranoid: false,
charset: 'utf8',
collate: 'utf8_general_ci',
});
}
static associate(db) {
db.Category.belongsToMany(db.Column, {
through: 'ColumnCategory',
unique: false,
});
}
};
model/index.js
const Sequelize = require('sequelize');
const User = require('./user');
const Baby = require('./baby_info');
const UserCase = require('./user_case');
const Column = require('./column_info');
const Tag = require('./tag_info');
const Category = require('./category_info');
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config')[env];
const db = {};
const sequelize = new Sequelize(config.database, config.username, config.password, config);
db.sequelize = sequelize;
db.User = User;
db.Baby = Baby;
db.UserCase = UserCase;
db.Column = Column;
db.Tag = Tag;
db.Category = Category;
User.init(sequelize);
Baby.init(sequelize);
UserCase.init(sequelize);
Column.init(sequelize);
Tag.init(sequelize);
Category.init(sequelize);
User.associate(db);
Baby.associate(db);
UserCase.associate(db);
Column.associate(db);
Tag.associate(db);
Category.associate(db);
module.exports = db;
error log
0|app | 21-01-04 16:09:26: TypeError: column.setCategorys is not a function
0|app | 21-01-04 16:09:26: at /home/ubuntu/bebenity/routes/column/column.ctrl.js:66:20
0|app | 21-01-04 16:09:26: at processTicksAndRejections (internal/process/task_queues.js:93:5)
0|app | 21-01-04 16:09:26: at async /home/ubuntu/bebenity/node_modules/sequelize/lib/sequelize.js:1090:24
0|app | 21-01-04 16:09:26: at async updateColumn (/home/ubuntu/bebenity/routes/column/column.ctrl.js:21:3)
Could you tell me what part of this code I've used relationship queries incorrectly?
Add 1
Actually, I've had a similar experience.
How to add child row in related table?? (Sequelzie N:M Relationship)
In that example, the method findOrCreate's callback value has a problem.
But, in this question, the method findOne's callback value is clearly Model Object! I have already checked through column instanceof Column that the column is the Column model instance.(It is true)
But it is a little bit different between model with Create method and findOne
Create Callback
findOne Callback
The solution was very simple...
Revising my column.setCategorys to column.setCategories was that...
OMG

Sequelize: refer a foreign key between 2 models

I'm trying to refer a foreign key between 2 models. but I'm getting this error:
throw new AssociationError(`${source.name}.belongsToMany(${target.name}) requires through option, pass either a string or a model`);
AssociationError [SequelizeAssociationError]: Order.belongsToMany(User) requires through option, pass either a string or a model
I check some similar questions but it didn't help.
I started working with Sequelize today so please give an example to answer.
db.js
const fs = require("fs");
const path = require("path");
const Sequelize = require("sequelize");
const basename = path.basename(module.filename);
const db = {};
const sequelize = new Sequelize("name", "user", "password", {
host: "localhost",
dialect: "mysql",
logging: false,
});
fs.readdirSync(__dirname).filter(file =>
(file.indexOf(".") !== 0) &&
(file !== basename) &&
(file.slice(-3) === ".js"))
.forEach(file => {
const model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
user.js
const Sequelize = require("sequelize");
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define("User",
{
id: {
type: Sequelize.BIGINT,
autoIncrement: true,
allowNull: false,
primaryKey: true,
},
email: Sequelize.STRING(60),
password: Sequelize.STRING(60),
fullName: {
type: Sequelize.STRING(60),
allowNull: true,
},
},
);
User.associate = function (models) {
models.User.belongsToMany(models.Order);
};
return User;
};
order.js
const Sequelize = require("sequelize");
module.exports = (sequelize, DataTypes) => {
const Order = sequelize.define("Order",
{
id: {
type: Sequelize.BIGINT,
autoIncrement: true,
allowNull: false,
primaryKey: true,
},
title: Sequelize.STRING(60),
orderNumber: Sequelize.STRING(60),
status: Sequelize.STRING(60),
amount: Sequelize.STRING(60),
trackingCode: Sequelize.STRING(60),
},
);
Order.associate = function(models) {
models.Order.belongsToMany(models.User);
};
return Order;
};
when I use lowercase for define name like this:
const User = sequelize.define("user",
{
...
}
);
const User = sequelize.define("order",
{
...
}
);
I get this error:
TypeError: Cannot read property 'belongsToMany' of undefined
sequelize: 5.21.6
I answered similar question here. Please take a look at it. Also pay attention to comments and to the link at the end of the discussion.
If you'll have any questions after reading feel free to ask them in comments to this answer.

SequelizeEagerLoadingError: (parent) is not associated to (child)!

I am building an application using sequelize. I currently have 3 tables; a User, a Tour, and a Location. The Location has a n:1 relationship with the Tour. The Tour has a n:1 relationship with the user.
Without the User association, the other two tables work fine. Once I add in the user association (and I have tried to do so through a migration AND by dropping and then recreating my entire database), I get a SequelizeEagerLoadingError: Location is not associated with Tour!
Here are my models:
module.exports = function(sequelize, DataTypes) {
var Location = sequelize.define("Location", {
title: {
type: DataTypes.STRING,
allowNull: false
},
description: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
len: [500]
}
},
address: {
type: DataTypes.TEXT,
allowNull: false
}
});
Location.associate = function(models) {
Location.belongsTo(models.Tour, {
onDelete: "cascade"
});
};
return Location;
};
module.exports = function(sequelize, DataTypes) {
var Tour = sequelize.define("Tour", {
title: {
type: DataTypes.STRING,
allowNull: false
},
description: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
len: [1, 1000]
}
},
neighborhood: {
type: DataTypes.STRING,
allowNull: false
},
URL: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
len: [1, 1000]
}
},
numberOfStops: DataTypes.INTEGER,
duration: {
type: DataTypes.INTEGER,
allowNull: false
},
tags: DataTypes.STRING
});
Tour.associate = function(models) {
Tour.hasMany(models.Location);
};
Tour.associate = function(models) {
Tour.belongsTo(models.User);
};
return Tour;
};
var bcrypt = require("bcrypt-nodejs");
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define("User", {
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true
}
},
password: {
type: DataTypes.STRING,
allowNull: false
}
});
User.prototype.validPassword = function(password) {
return bcrypt.compareSync(password, this.password);
};
User.hook("beforeCreate", function(user) {
user.password = bcrypt.hashSync(
user.password,
bcrypt.genSaltSync(10),
null
);
});
User.associate = function(models) {
User.hasMany(models.Tour);
};
return User;
};
And here is the include statement where it is failing, and where we establish the link with the tourId to the location:
app.get("/tour/:id", function(req, res) {
db.Tour.findOne({
where: { id: req.params.id },
include: [db.Location]
}).then(function(tour) {
res.render("tour", {
tour: tour
});
});
});
var API = {
saveTour: function(tour) {
return $.ajax({
headers: {
"Content-Type": "application/json"
},
type: "POST",
url: "api/tours",
data: JSON.stringify(tour)
});
},
saveLocations: function(locations) {
return $.ajax({
headers: {
"Content-Type": "application/json"
},
type: "POST",
url: "api/locations",
data: JSON.stringify(locations)
});
},
getUserId: function() {
return $.ajax({
type: "GET",
url: "api/user_data"
});
}
};
var tour = {
Users: thisUser.getUserId(),
title: title,
description: description,
neighborhood: neighborhood,
URL: URL,
duration: duration,
tags: tags
};
// console.log(tour);
if (!errors.length) {
// Post our tour to the Tours table, then reveal the form and set our local tour object.
API.saveTour(tour).then(function(tour) {
document.getElementById("submit-tour").remove();
document.getElementById("tourstopssection").style.display = "block";
thisTour.setId(tour.id);
});
}
}
// Function takes in the newly created tour object, grabs DOM values for each.
function addTourLocations(e) {
e.preventDefault();
// Grab and process all of our tour stops.
var locationElements = document.getElementsByClassName("tourstop");
var areStopErrors = false;
var locations = [];
// Loop over every location element on the DOM.
for (var j = 0; j < locationElements.length; j++) {
var children = locationElements[j].children;
// Initialize this location with the tour id; we'll pass in data...
var thisLocation = {
TourId: thisTour.getId()
};
// ... by looping over the DOM children and grabbing their form values.
for (var k = 0; k < children.length; k++) {
if (
children[k].classList.value.includes("stoptitle") &&
children[k].value
) {
var stopTitle = children[k].value;
thisLocation.title = stopTitle;
}
if (
children[k].classList.value.includes("stopaddress") &&
children[k].value
) {
var stopAddress = children[k].value;
thisLocation.address = stopAddress;
}
if (
children[k].classList.value.includes("stopdescription") &&
children[k].value
) {
var stopDescription = children[k].value;
thisLocation.description = stopDescription;
}
}
// Push this location into our locations array.
locations.push(thisLocation);
Finally, this is how the app/db are synced:
require("dotenv").config();
var express = require("express");
var session = require("express-session");
var exphbs = require("express-handlebars");
var helpers = require("./lib/helpers");
var db = require("./models");
var passport = require("./config/passport");
var app = express();
var PORT = process.env.PORT || 3000;
// Middleware
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static("public"));
var hbs = exphbs.create({
defaultLayout: "main",
helpers: helpers // Require our custom Handlebars helpers.
});
//Sessions are used to keep track of our user's login status
app.use(
session({ secret: "keyboard cat", resave: true, saveUninitialized: true })
);
app.use(passport.initialize());
app.use(passport.session());
app.use(function(req, res, next) {
res.locals.user = req.user; // Set a local variable for our user.
next();
});
// Handlebars
app.engine("handlebars", hbs.engine);
app.set("view engine", "handlebars");
// Routes
require("./routes/apiRoutes")(app);
require("./routes/htmlRoutes")(app);
var syncOptions = { force: false };
// If running a test, set syncOptions.force to true
// clearing the `testdb`
if (process.env.NODE_ENV === "test") {
syncOptions.force = true;
}
// Starting the server, syncing our models ------------------------------------/
db.sequelize.sync(syncOptions).then(function() {
app.listen(PORT, function() {
console.log(
"==> 🌎 Listening on port %s. Visit http://localhost:%s/ in your browser.",
PORT,
PORT
);
});
});
module.exports = app;
I've been googling for four days....help!
Try adding this to your associations, also why are you defining twice the association function on Tour?
module.exports = function(sequelize, DataTypes) {
var Location = sequelize.define("Location", {
//
});
Location.associate = function(models) {
Location.belongsTo(models.Tour, { as:'Tour', foreignKey:'tourId', onDelete: "cascade"});
};
return Location;
};
module.exports = function(sequelize, DataTypes) {
var Tour = sequelize.define("Tour", {
//
});
Tour.associate = function(models) {
Tour.hasMany(models.Location, { as: 'Locations', foreignKey: 'tourId'});
Tour.belongsTo(models.User, { as: 'User', foreignKey: 'userId' });
};
return Tour;
};
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define("User", {
//
});
User.associate = function(models) {
User.hasMany(models.Tour, {as: 'Tours', foreignKey: 'userId'});
};
return User;
};
And add the same on the query.
db.Tour.findOne({
where: { id: req.params.id },
include: [{
model: db.Location,
as: 'Locations'
}]
}).then(function(tour) {
res.render("tour", {
tour: tour
});
});
I figured it out - the fact that I had defined the association on the tours model twice was breaking everything. Once I combined them as mentioned above, everything worked perfectly!
One other thing to note - sequelize automatically assigns the foreign key and the alias, so I left that part out.

Creating row in both source and association with Sequelize many to many model

I have a many to many relationship between a user and a group. A user has many groups and a group has many users.
I have a users table, a groups table and junction table called usersGroups.
My User model:
'use strict';
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
email: DataTypes.STRING,
username: DataTypes.STRING,
facebookId: DataTypes.STRING,
password: DataTypes.STRING,
}, {
classMethods: {
associate: function(models) {
User.hasMany(models.Payment);
User.hasMany(models.Friend, {foreignKey: 'userIdLink1', allowNull: false});
User.belongsToMany(models.Group, { as: 'Groups', through: 'usersGroups', foreignKey: 'userId' });
}
},
instanceMethods: {
toJSON: function () {
var values = Object.assign({}, this.get());
delete values.password;
return values;
}
}
});
return User;
};
My group model
'use strict';
module.exports = function(sequelize, DataTypes) {
var Group = sequelize.define('Group', {
}, {
classMethods: {
associate: function(models) {
// associations can be defined here
Group.belongsToMany(models.User, { as: 'Users', through: 'usersGroups', foreignKey: 'groupId' });
}
},
instanceMethods: {
toJSON: function () {
var values = Object.assign({}, this.get());
delete values.password;
return values;
}
}
});
return Group;
};
When I try create a new group with associated user with the following 2 methods, it creates a new group but no association
const values = {
userId: 1
}
const options = {
include: db.Users
}
db.Group
.create(values, options)
.then( (group) => {
res.send(group)
}).catch(err => {
res.status(500).send({err: err})
})
or
db.Group
.create()
.then( (group) => {
group.addUser({ userId: 1 }).then(result => {
res.send(result)
}).catch(err => {
res.status(500).send({err: err})
})
}).catch(err => {
res.status(500).send({err: err})
})
If you simply want to assign user to newly created group, you need to use addUser, just like you did, but this method accepts first parameter as instance of Model or ID of instance, just like the documentation says
An instance or primary key of instance to associate with this.
So you would have to perform group.addUser(userId).then(...) which in your case would be group.addUser(1).then(...).

Create row including association with hasOne in Sequelize

I'm testing different ORM's for Node.js and got stuck at this error:
Possibly unhandled TypeError: undefined is not a function
# person.setUser(user);
Tried person.setUsers, user.setPerson and user.setPeople. Also tried console.log to find the function with no luck.
What am I doing wrong?
var config = require('./config.json');
var Sequelize = require('sequelize');
var sequelize = new Sequelize(config.connection, {
define: {
freezeTableName: true,
underscoredAll: true,
underscored: true
}
});
var Person = sequelize.define('person', {
first_name: Sequelize.STRING,
last_name: Sequelize.STRING
});
var User = sequelize.define('user', {});
Person.hasOne(User);
sequelize.sync().then(run);
function run() {
var person = Person.create({ first_name: 'Markus', last_name: 'Hedlund' });
var user = User.create();
person.setUser(user);
}
I think what you want to do is
Person.create({ first_name: 'Markus', last_name: 'Hedlund' }).then((person) => {
User.create().then((user) => {
person.setUser(user);
});
});
Although dege answer is correct I would write it with a nice promise chain:
Person.create({ first_name: 'Markus', last_name: 'Hedlund' })
.bind({})
.then(function(person){
this.person = person;
return User.create()
})
.then(function(user){
return this.person.setUser(user);
});