Here's my query that's failing:
Models.OrdersProducts.create({
orderId: 1,
productId: 1,
});
with the error:
Executing (default): INSERT INTO "OrdersProducts" ("orderId","productId","createdAt","updatedAt","OrderId") VALUES (1,1,'2018-02-25 12:51:00.110 +00:00
','2018-02-25 12:51:00.110 +00:00',NULL) RETURNING *;
Unhandled rejection SequelizeDatabaseError: column "OrderId" of relation "OrdersProducts" does not exist
at Query.formatError (/Users/aakashverma/Documents/sequelize-join-table/node_modules/sequelize/lib/dialects/postgres/query.js:363:16)
where my table doesn't have the column OrderId(with capital O) and only orderId
NOTE: My Orders and Products tables do have an entry with id 1, that's not the problem.
This is my migration for OrdersProducts:
module.exports = {
up: (queryInterface, Sequelize) => queryInterface.createTable('OrdersProducts', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
orderId: {
type: Sequelize.INTEGER,
references: {
model: 'Orders',
key: 'id',
},
},
productId: {
type: Sequelize.INTEGER,
references: {
model: 'Products',
key: 'id',
},
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
}),
down: (queryInterface, Sequelize) => queryInterface.dropTable('OrdersProducts'),
};
and here are the models file:
models/OrdersProducts.js
module.exports = (sequelize, DataTypes) => {
const OrdersProducts = sequelize.define('OrdersProducts', {
orderId: DataTypes.INTEGER,
productId: DataTypes.INTEGER,
}, {});
return OrdersProducts;
};
models/Orders.js
module.exports = (sequelize, DataTypes) => {
const Orders = sequelize.define('Orders', {
userId: DataTypes.INTEGER,
}, {});
Orders.associate = function (models) {
Orders.belongsTo(models.Users);
Orders.belongsToMany(models.Products, { through: 'OrdersProducts', as: 'product' });
};
return Orders;
};
models/Products.js
module.exports = (sequelize, DataTypes) => {
const Products = sequelize.define('Products', {
name: DataTypes.TEXT,
}, {});
Products.associate = function (models) {
Products.belongsToMany(models.Orders, { through: 'OrdersProducts', as: 'order' });
};
return Products;
};
Weird.
N.B. I am using 1 as the id in queries because this is the autoincrement id key value as I only add one entry in any table whatsoever.
Looking at my Orders model:
module.exports = (sequelize, DataTypes) => {
const Orders = sequelize.define('Orders', {
userId: DataTypes.INTEGER,
}, {});
Orders.associate = function (models) {
Orders.belongsTo(models.Users);
Orders.belongsToMany(models.Products, { through: 'OrdersProducts', as: 'product' });
};
return Orders;
};
and myProducts model:
module.exports = (sequelize, DataTypes) => {
const Products = sequelize.define('Products', {
name: DataTypes.TEXT,
}, {});
Products.associate = function (models) {
Products.belongsToMany(models.Orders, { through: 'OrdersProducts', as: 'order' });
};
return Products;
};
These two seem to create attributes of their own for my OrdersProducts table as OrderId and ProductId (with first letter capital; don't know why and how they are generating the name) and therefore, I was getting that OrderId thingy.
If I remove the belongToMany association from the Orders model, I stared to get the same error with ProductId column instead.
Finally, I found the accepted answer here which told me, in a way, to use the columns provided by the associations and drop the corresponding in the OrdersProducts column.
Now my query, which works fine BTW, looks like:
const Models = require('./models');
// Models.Users.create({
// name: 'Aakash',
// });
// Models.Orders.create({
// userId: 1,
// });
// Models.Products.create({
// name: 'lash',
// });
Models.OrdersProducts.create({
OrderId: 1,
ProductId: 1,
});
and model looks like (pay attention to the capital letters, again):
module.exports = (sequelize, DataTypes) => {
const OrdersProducts = sequelize.define('OrdersProducts', {
OrderId: DataTypes.INTEGER,
ProductId: DataTypes.INTEGER,
}, {});
return OrdersProducts;
};
The mystery about the automatic column naming still exists.
P.S. This is the weirdest part.
Now I have a table Users as you'd have been able to see from my code above. Pay attention to how the belongsTo plays in the models.
models/users.js
module.exports = (sequelize, DataTypes) => {
const Users = sequelize.define('Users', {
name: DataTypes.STRING,
}, {});
Users.associate = function (models) {
Users.hasMany(models.Orders);
};
return Users;
};
models/orders.js
module.exports = (sequelize, DataTypes) => {
const Orders = sequelize.define('Orders', {
userId: DataTypes.INTEGER,
}, {});
Orders.associate = function (models) {
Orders.belongsTo(models.Users);
Orders.belongsToMany(models.Products, { through: 'OrdersProducts', as: 'product' });
};
return Orders;
};
The query below still works and adds an entry to Orders (look at how it doesn't require me to remove userId column from the Orders table nor does it come up with its own UserId -_-):
Models.Users.create({
name: 'Aakash',
});
Models.Orders.create({
userId: 1,
});
models/users.js
module.exports = (sequelize, DataTypes) => {
const Users = sequelize.define('Users', {
name: DataTypes.STRING,
}, {});
Users.associate = function (models) {
Users.hasMany(models.Orders);
};
return Users;
};
models/orders.js
module.exports = (sequelize, DataTypes) => {
const Orders = sequelize.define('Orders', {
userId: DataTypes.INTEGER,
}, {});
Orders.associate = function (models) {
Orders.belongsTo(models.Users);
Orders.belongsToMany(models.Products, { through: 'OrdersProducts', as: 'product' });
};
return Orders;
};
Related
Im trying to create a sequalized query that Searches For a Team Name & Filter To Sport Type but when I test the JSON body on Postman I get an error and its not returning the data. The JSON body matches the data that its meant to return but its not matching up.
Test on Postman
{
"searchTerm": "Kaizer fc",
"sportType": "2"
}
teams.js
const Teams = require('../models').teams;
const {sequelize, QueryTypes } = require('sequelize');
const db = require('../models')
const search = (searchTerm, sportType) => {
return new Promise(async (resolve, reject) => {
try {
console.log("Testing");
const teams = await db.sequelize.query(
`SELECT teams.name, institutions.name, addresses.line1, addresses.line2, addresses.country
FROM teams
INNER JOIN institutions
ON teams.institution_id = institutions.id
INNER JOIN addresses
ON institutions.address_id = addresses.id
WHERE teams.name like :search_name and teams.sport_type_id LIKE :sport_type`,
{
replacements: { search_name: searchTerm, sport_type: sportType },
type: QueryTypes.SELECT
}
);
return resolve(teams);
} catch (err) {
return reject(err)
}
})
}
teams.js - Models Folder
'use strict';
module.exports = (sequelize, DataTypes) => {
const teams = sequelize.define('teams', {
name: { type: DataTypes.STRING, allowNull: false },
media_id: { type: DataTypes.STRING, allowNull: true },
state_id: { type: DataTypes.INTEGER, allowNull: true },
status_id: { type: DataTypes.INTEGER, allowNull: true },
sport_type_id: { type: DataTypes.INTEGER, allowNull: false },
created_by: { type: DataTypes.INTEGER, allowNull: true, references: { model: 'users', key: 'id' } },
modified_by: { type: DataTypes.INTEGER, allowNull: true, references: { model: 'users', key: 'id' } },
primary_user_id: { type: DataTypes.INTEGER, allowNull: true, references: { model: 'users', key: 'id' } },
institution_id: { type: DataTypes.INTEGER, allowNull: true, references: { model: 'institutions', key: 'id' } },
}, {
createdAt: 'created_at',
updatedAt: 'updated_at',
indexes: [
{
unique: true,
fields: ['id']
}
],
});
return teams;
};
search.js - Controllers
const helper = require('../utils/helper');
const teamsService = require('../services/teams');
const search = async (req, res) => {
try {
const data = await teamsService.search(req.body);
console.log("TESTING");
console.log(data);
return res.send(data);
} catch (err) {
return helper.handleError(err, req, res);
}
}
module.exports = search;
search function has two arguments: searchTerm and sportType and you pass the whole req.body as a first argument so that's why it becomes a value for searchTerm and you got this error about the whole value from Sequelize.
Just extract both props from req.body OR define search with props passed by as an object:
const { searchTerm, sportType } = req.body;
const data = await teamsService.search(searchTerm, sportType);
OR
const data = await teamsService.search(req.body);
...
const search = ({ searchTerm, sportType }) => {
return new Promise(async (resolve, reject) => {
This is my Cliente.js that its a model
const Sequelize = require('sequelize');
module.exports = function(sequelize, DataTypes) {
const cliente = sequelize.define('cliente', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true
},
nombre: {
type: DataTypes.STRING(20),
allowNull: true
}
}, {
sequelize,
tableName: 'cliente',
timestamps: false,
indexes: [
{
name: "PRIMARY",
unique: true,
using: "BTREE",
fields: [
{ name: "id" },
]
},
]
});
return cliente;
};
and that is my app.js
var express = require('express');
const Sequelize = require('sequelize');
const Cliente = require("./Modelos/cliente")
var app = express();
const db = require("./database/db")
db.sequelize.authenticate().then(() => {
console.log('Connection has been established successfully.');
console.log(Cliente)
}).catch(err => {
console.error('Unable to connect to the database:', err);
});
The line "console.log(Cliente) returns me "[Function]" and not the model.
how can i get the model and not the function?
So try changing this line
module.exports = function(sequelize, DataTypes) {
To
exports.sequ = function(sequelize, DataTypes) {
Then
Change
const Cliente = require("./Modelos/cliente");
And this line to
console.log(Cliente.sequ)
I would suggest rereading how to work with sequelize and rewrite the codebase.
Cliente.js - exports the function with has 2 parameters.
console.log(Cliente) - doesn't pass any parameters. Thus how the magic should happen?
Cliente.js - const Sequelize = require('sequelize') is not used.
The models must be defined on the sequelize instance which you are using also connect to DB.
//Cliente.js
const DataTypes = require("sequelize");
const cliente = sequelize => {
const res = sequelize.define('cliente', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true
},
nombre: {
type: DataTypes.STRING(20),
allowNull: true
}
}, {
sequelize,
tableName: 'cliente',
timestamps: false,
indexes: [
{
name: "PRIMARY",
unique: true,
using: "BTREE",
fields: [
{ name: "id" },
]
},
]
});
return res;
};
module.exports = cliente
and
// index.js
const Sequelize = require('sequelize')
const sequelize = new Sequelize('postgres://<username>:<password>#<host>:<port>/<db_name>')
;(async () => {
await sequelize.authenticate()
const Cliente = require("./cliente")
const cliente = Cliente(sequelize)
console.log(cliente)
})()
I'm trying to learn Sequelize.js and I'm confused about its Many-To-Many Association.
What I've tried to do is simple Tasks Management with Users. Each task can be assignable to other users.
So, there's Users, Tasks and TaskContributors tables.
First, I made the POC version of my idea with Express.js. Then I found that I don't know how to insert to the Relational Table within different router.
Here are the model codes.
User Model
'use strict'
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define(
'User',
{
uid: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4 },
name: DataTypes.STRING,
password: DataTypes.STRING,
},
{},
)
User.associate = function (models) {
User.belongsToMany(models.Task, {
as: 'Contributors',
through: 'TaskContributors',
foreignKey: 'userId',
})
}
return User
}
Task Model
'use strict'
module.exports = (sequelize, DataTypes) => {
const Task = sequelize.define(
'Task',
{
uid: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4 },
name: DataTypes.STRING,
description: DataTypes.TEXT,
status: DataTypes.BOOLEAN,
},
{},
)
Task.associate = function (models) {
Task.belongsToMany(models.User, {
as: 'Task',
through: 'TaskContributors',
foreignKey: 'taskId',
})
}
return Task
}
TaskContributor Model
'use strict'
module.exports = (sequelize, DataTypes) => {
const TaskContributor = sequelize.define(
'TaskContributor',
{
userId: {
allowNull: false,
type: DataTypes.INTEGER,
references: { model: 'Users', key: 'id' },
},
taskId: {
allowNull: false,
type: DataTypes.INTEGER,
references: { model: 'Tasks', key: 'id' },
},
userStatus: { allowNull: false, type: DataTypes.STRING },
},
{},
)
TaskContributor.associate = function (models) {}
return TaskContributor
}
Routers
Users Router
router.get('/create/:name', (req, res) => {
User.create({ name: req.params.name, password: '123' })
.then((result) => res.send(result))
.catch((err) => res.status(500).send(err))
})
Tasks Router
router.get('/create/:userId/:name', (req, res) => {
const { userId, name } = req.params
User.findOne({ where: { uid: userId } }).then(async (user) => {
console.log(user)
const maybeTask = await user
.addTask({
name,
description: '',
status: false,
through: { userStatus: 'owner' },
})
.catch((err) => err)
if (maybeTask instanceof Error) res.status(500).send(maybeTask)
res.send(maybeTask)
})
})
When I tried to create new Task, it said user.addTask is not a function.
From what I understand from the Docs is that they showed how to create M-M association with two model.create() Objects, but not with the scenario like creating in different file.
My Product model:
const { Model, DataTypes } = require('sequelize');
class Product extends Model {
static init(connection) {
super.init({
name: DataTypes.STRING,
description: DataTypes.TEXT,
purchase_price: DataTypes.DOUBLE,
sale_price: DataTypes.DOUBLE
}, {sequelize: connection});
}
static associate(models) {
this.belongsToMany(models.Purchase, {
foreignKey: 'product_id', through: 'products_purchases', as: 'purchases'
});
}
}
module.exports = Product;
My Purchase Model:
const { Model, DataTypes } = require('sequelize');
const Product = require('../models/Product');
class Purchase extends Model {
static init(connection) {
super.init({
request_number: DataTypes.STRING,
datetime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
email: DataTypes.STRING,
status: DataTypes.ENUM([
'orderPlaced', 'paymentMade','paymentConfirmed', 'forwardedProduct','productReceived','orderCanceled'
])
}, {sequelize: connection});
}
static associate(models) {
this.belongsTo(models.User, {foreignKey: 'user_id', as: 'user'});
this.belongsToMany(models.Product, {
foreignKey: 'purchase_id', through: 'products_purchases', as: 'products'
});
}
}
module.exports = Purchase;
And finally my ProductPurchase Model:
(Note that there is some extra columns in the relationship table)
const { Model, DataTypes } = require('sequelize');
class ProductPurchase extends Model {
static init(connection) {
super.init({
product_value: DataTypes.FLOAT,
product_quantity: DataTypes.INTEGER
}, {
sequelize: connection,
modelName: 'products_purchases'
});
}
}
module.exports = ProductPurchase;
I want to insert data into purchases table and also into products_purchases. I tried to do it the way below, but I don't know how to send the data of the extra columns from ProductPurchase:
async store(req, res) {
try {
const { user_id } = req.params;
const user = await User.findByPk(user_id);
if (!user) {
return res.status(400).json('User not found!');
}
// productsData = [{ productId, productPrice, quantity }];
const { request_number, datetime, email, status, productsData } = req.body;
const purchase = await Purchase.create({
request_number, datetime, email, status, user_id
});
const productsIds = productsData.map(product => {
return product.productId;
});
const products = await Product.findAll({
where: {id: productsIds}
});
await purchase.addProduct(products);
return res.json(products);
} catch (error) {
return res.status(500).json(error);
}
}
Can anybody help me?
I'm trying to use a sequelize N:M relation trough another table but I keep getting this error:
throw new Error(${this.name}.belongsToMany called with something that's not a subclass of Sequelize.Model);
Error: Cases.belongsToMany called with something that's not a subclass of Sequelize.Model
Here are my classes:
models/User.js
const Sequelize = require('sequelize');
const sql = require('../config/sql');
const DocumentType = require('./DocumentType');
const Case = require('./Case');
const User = sql.define('Users', {
firstName: Sequelize.STRING,
lastName: Sequelize.STRING,
email: Sequelize.STRING,
document: Sequelize.INTEGER,
documentTypeId: Sequelize.INTEGER,
password: Sequelize.STRING,
active: Sequelize.INTEGER
});
User.belongsTo(DocumentType, {foreignKey: 'documentTypeId' ,as: 'documentType'});
User.belongsToMany(Case, { through: 'CaseUser' });
User.findById = (id) => {
return User.findOne({
where: {
id: id
},
include: 'documentType'
});
};
User.findByEmail = (email) => {
return User.findOne({
where: {
email: email
},
include: 'documentType'
});
};
User.checkActiveStatus = (id) => {
return User.findOne({
where: {
id: id
},
attributes: ['active']
});
};
module.exports = User;
models/Case.js
const Sequelize = require('sequelize');
const sql = require('../config/sql');
const User = require('./User');
const Case = sql.define('Cases', {
description: Sequelize.STRING,
startDate: Sequelize.STRING
});
Case.belongsToMany(User, {through: 'CaseUser'});
module.exports = Case;
I get the error only in the Case.belongsToMany(User, { through: 'CaseUser' }); and not in the User.belongsToMany(Case, { through: 'CaseUser' }); one
The weird thing is that if I switch the belongsToMany(User... for belongsToMany(DocumentType... and import the DocumentType file I don't get the error. The DocumentType Model is virtually identical to the User one
models/DocumentType.js
const Sequelize = require('sequelize');
const sql = require('../config/sql');
const DocumentType = sql.define('DocumentTypes', {
name: Sequelize.STRING,
slug: Sequelize.STRING
}, {
timestamps: false
});
module.exports = DocumentType;
Any ideas on what could be causing this behavior?
Thanks!
You should try to avoid circular dependencies.
Remove lines
const Case = require('./Case');
and
Case.belongsToMany(User, {through: 'CaseUser'});
from User.js
Remove lines
const User = require('./User');
and
User.belongsToMany(Case, { through: 'CaseUser' });
from Case.js
Create associations.js
const Case = require('./Case');
const User = require('./User');
Case.belongsToMany(User, {through: 'CaseUser'});
User.belongsToMany(Case, { through: 'CaseUser' });