I'm using sequelize v3.11.0 and sails v0.11.0 using MySQL DB.
I have my models/User.js
module.exports = {
attributes: {
firstName: {
type: Sequelize.STRING,
allowNull: false,
field:'first_name'
},
lastName: {
type: Sequelize.STRING,
field:'last_name'
},
phone: {
type: Sequelize.STRING
}
}
}
model/Category.js
module.exports = {
attributes: {
name: {
type: Sequelize.STRING,
allowNull:false,
unique:true,
},
description: {
type: Sequelize.STRING
}
}
}
model/UsersCategory.js
module.exports = {
attributes: { },
options: {
tableName: 'user_categories'
},
associations: function() {
User.belongsToMany(Category, {
through: UsersCategory,
foreignKey: {
name:'userId',
field:'user_id'
}
});
Category.belongsToMany(User, {
through: UsersCategory,
foreignKey: {
name:'categoryId',
field:'category_id'
}
});
}
};
But when I'm executing this code In my database user_categories table I'm geting the attribute as:
category_id , userId
I'm not getting that why userId in camelcase.
when I'm doing:
User.findAll({
include: [
{all:true}
]
})
I'm getting error:
"ER_BAD_FIELD_ERROR: Unknown column 'Categories.UsersCategory.user_id' in 'on clause'"
But If I user userId and CategoryId in my UserCategory model then It working Fine.
Is there is some problem with the Field in many to many association?
Related
I have 2 models:
class User extends Model {
static associate(models) {
User.hasMany(models.Role, {
foreignKey: 'userId'
});
}
};
User.init({
firstname: {
type: DataTypes.STRING,
},
lastname: {
type: DataTypes.STRING,
},
allowedApps: {
type: DataTypes.ENUM({
values: Object.keys(PORTALS)
}),
allowNull: false
}
}, {
sequelize,
paranoid: true,
modelName: 'User',
});
class Role extends Model {
static associate(models) {
Role.BelongsTo(models.User, {
foreignKey: 'userId'
});
}
};
Role.init({
type: {
type: DataTypes.STRING,
unique: true
},
name: DataTypes.STRING,
userId: {
type: DataTypes.INTEGER,
allowNull: false,
}
}, {
sequelize,
paranoid: true,
modelName: 'Role',
});
I would like to get all users where the firstname OR the role type matches a certain condition. Something like:
User
.findAndCountAll({
where: {
$or: [
{
firstname: "John Doe"
},
{
"$Role.type$": "Admin"
}
]
},
include: [{
model: Role,
}],
}).limit=10,offset=0
.then(users => res.status(200).send(users))
.catch(error => {
return res.sendStatus(500);
});
above query giving me error: "SequelizeDatabaseError: Unknown column 'Role.type' in 'field list'"
I want to search through child model when it has one to many relationship having my limit and offset intact.Same query would give me success if user would have HasOne relation with role.
This is just an example code of what I try to achieve so please ignore any typos and silly mistakes.
After some digging:
await User.findAll({
where: {
$or: [
{
firstname: "John Doe"
},
{
"$Role.type$": "Admin"
}
]
},
include: {
model: Role,
as: 'Role',
required: false
}
});
However, it doesn't make logical sense to select Users that have no associated Role (required: false), while querying such Users with a property that exists on Role ($or: $Role.type$). If we set Required = true, then we violate your initial condition
firstname OR the role type matches a certain condition.
The following addresses this problem:
await User.findAll({
include: {
model: Role,
required: false
}
})
.then(
users => users
.filter(user => user?.firstName === "John Doe" || user.role?.type ===
"Admin");
);
I have two model that are belongs to each other (order_items.js & products.js) productId as a foreign key in order_items, code as below:
order_items.js
const { DataTypes } = require('sequelize')
const db_config = require(`../config/config`)
const Product = require('./product')
const OrderItem = db_config.define('order_item', {
productId : { type: DataTypes.INTEGER, allowNull:false, references: {model: Product, key: 'id'} },
quantity: { type: DataTypes.INTEGER }
}, {
freezeTableName: true
})
module.exports = OrderItem
product.js
const { DataTypes } = require('sequelize')
const db_config = require(`../config/config`)
const Category = require('./category')
const Product = db_config.define('product', {
productName : { type: DataTypes.STRING, allowNull:false },
productPrice: { type: DataTypes.INTEGER, allowNull:false },
productDescription: { type: DataTypes.STRING, allowNull:true },
productImage: { type: DataTypes.STRING, allowNull:true },
productStock: { type: DataTypes.INTEGER, validate: { min: 0 }, defaultValue: 0, allowNull: false },
CategoryId: { type: DataTypes.INTEGER, allowNull:false, defaultValue: 1, references: {model: Category, key: 'id'}}
}, {
freezeTableName: true
})
module.exports = Product
order_routes.js
router.get('/', async (req, res) => {
try {
const dataList = await OrderItem.findAll({include: [{model:Product, required:true}]})
res.send({
status: "success",
message: "data found",
data: dataList
})
} catch (err) {
res.send({
status: "failed",
message: err})
}
})
Result in postman
Can anyone help please? what I'm trying to do is that when I get the order_item, it also get the products refers to the id of the products
Where are the associations in the model definition? I see a reference on column field but you also needs to do below definitions seperately
Inside OrderItem Model File
OrderItem.associate = models => {
OrderItem.belongsTo(Product, {as: "product", foreignKey: "productId", sourceKey: "id"});
};
Inside Products Model File
Product.associate = models => {
Product.hasMany(OrderItem, {as: "orders", foreignKey: "productId", sourceKey: "id"});
};
Also I would suggest you to store price in OrderItem collection as well so in case in future when the product price changes your past order data is not incorrect.
Using Sequelize with MySQL. I have three models. Consultant, FamilyMember and Appointments. Appointment refers to Consultant and FamilyMember.
I have defined the foreign keys in the Appointment model. When the DB is created - the foreign keys are visible - when I check through a MySQL client, on the appointment table. The table names are freeze - so there isn't any chance of pluralization of the table names.
Consultant Model:
module.exports = (sequelize, DataTypes) => {
const consultant = sequelize.define('consultant', {
ID: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false
},
FirstName: {
type: DataTypes.STRING,
allowNull: false
},
LastName: {
type: DataTypes.STRING,
allowNull: false
}
{
freezeTableName: true
}
);
return consultant;
};
Appointment Model:
module.exports = (sequelize, DataTypes) => {
const appointment = sequelize.define('appointment', {
// attributes
ID: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false
},
ConsultantID: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'consultant',
key: 'ID'
}
},
FamilyMemberID: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'familymember',
key: 'ID'
}
}
},
{
freezeTableName: true
}
);
appointment.associate = function (models) {
models.appointment.belongsTo(models.consultant, {
foreignKey: 'ConsultantID',
as: 'consultant',
});
models.appointment.belongsTo(models.familymember, {
foreignKey: 'FamilyMemberID',
as: 'familymember',
});
};
return appointment;
};
Family Member model:
module.exports = (sequelize, DataTypes) => {
const familymember = sequelize.define('familymember', {
// attributes
ID: {
primaryKey: true,
type: DataTypes.UUID,
allowNull: false
},
FamilyID: {
type: DataTypes.UUID,
allowNull: false
},
FirstName: {
type: DataTypes.STRING,
allowNull: false
},
LastName: {
type: DataTypes.STRING,
allowNull: false
}
},
{
freezeTableName: true
}
);
return familymember;
};
Then in the code I try to fetch appointment and get the related familymember and consultant like this
var appointments = await Appointment.findAll({
where: {
AppointmentDateConfirmed: {
$gte: moment().subtract(0, 'days').toDate()
}
}, include:[Consultant, FamilyMember]
}
)
However I get an error
UnhandledPromiseRejectionWarning: SequelizeEagerLoadingError: consultant is not associated to appointment!
I suppose you should register your associations after models registration like I pointed in this answer
I am using sequelize for my backend and I want to add a where condition with YYYY-mm-dd
In mysql we use date_format(dateCreated, "%d-%m-%Y").
But how to achieve it in Sequelize. I searched all over the google but nothing helped me out
My present Sequelize query. I want to get data of dateCreated = '2020-05-31'.
const apartmentOrdersData = await apartments_order.findAll(
{
where: { apid: req.body.apid }, group: ['apcid'],
attributes: ['apcid', [sequelize.fn('sum', sequelize.col('totalCost')), 'total_amount'],],
include: [apartments_child]
});
My model:
const { DataTypes, Model } = require('sequelize');
const sequelize = require('../../../mysql_connection/sequilize');
const admins = require('./admins');
const apartments_child = require('./apartments_child');
class apartments_order extends Model { }
apartments_order.init({
// Model attributes are defined here
apoid: {
type: DataTypes.INTEGER,
primaryKey: true
},
invoiceNo: {
type: DataTypes.STRING
},
apid: {
type: DataTypes.INTEGER
},
apcid: {
type: DataTypes.INTEGER
},
apcbid: {
type: DataTypes.INTEGER
},
totalCost: {
type: DataTypes.DECIMAL
},
dateCreated: {
type: DataTypes.DATE
},
dateUpdated: {
type: DataTypes.DATE
},
createdBy: {
type: DataTypes.STRING
},
updatedBy: {
type: DataTypes.STRING
},
status: {
type: DataTypes.STRING
}
}, {
sequelize,
timestamps: false,
logging: false,
tableName: 'apartments_order'
});
apartments_order.hasOne(admins, { foreignKey: 'aid', sourceKey: 'createdBy' });
apartments_order.hasOne(apartments_child, { foreignKey: 'apcid', sourceKey: 'apcid' });
module.exports = apartments_order;
One thing that you can do is use a setter and getter for the columns.
Follow an example (on your field declaration, you can manipulate the data inside getter() and setter():
dateUpdated: {
type: Sequelize.STRING,
defaultValue: '[]',
get() {
const d = this.getDataValue('dateUpdated');
return format(d, 'Y-m-d');
},
set(value) {
return this.setDataValue('dateUpdated', format(value, <your-format-here>)
},
type: DataTypes.DATE,
},
I'm working with Sequelize 5.7, trying to utilize virtual datatype,
to pull related information into a model.
Given simplified company and user models, how do I get company.name
into user.companyname ?
company
let Schema = sequelize.define(
"company",
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
name: {
type: DataTypes.STRING(45)
}
}
);
user
let Schema = sequelize.define(
"user",
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
login: {
type: DataTypes.STRING(45),
unique: true
},
company: {
type: DataTypes.INTEGER.UNSIGNED,
references: {
model: sequelize.model('company'),
key: 'id'
}
},
/* This companyname contruct is pure fantasy, and the target of my question */
companyname: {
type: new DataTypes.VIRTUAL(DataTypes.STRING,['company']),
references: {
model: 'company',
key: 'name'
}
}
}
);
In your case, I think it is a better idea to use a relationship (an association)
Sequelize Associations
const User = sequelize.define('user', {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
login: {
type: DataTypes.STRING(45),
unique: true
},
company_id: {
type: DataTypes.INTEGER.UNSIGNED,
},
});
const Company = sequelize.define('company', {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
},
});
User.belongsTo(Company, {
foreignKey: 'company_id', // you can use this to customize the fk, default would be like companyId
});
Company.hasMany(User);
Then when calling your model you do something like:
User.findAll({ include: Company }).then(users => console.log(users));
I solved the problem by using type: DataTypes.VIRTUAL in model
const { Model, DataTypes } = require('sequelize');
class User extends Model {
static init(sequelize) {
super.init({
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
login: {
type: DataTypes.STRING(45),
unique: true
},
company_id: {
type: DataTypes.INTEGER.UNSIGNED,
},
companyname:{
type: DataTypes.VIRTUAL,
get() {
return this.Company?.get().name;
},
set(/*value*/) {
throw new Error('Do not try to set the `companyname` value!');
}
},
}, {
sequelize
})
}
static associate(models) {
this.belongsTo(Company, {
foreignKey: 'company_id',
});
}
}
module.exports = User;
to search just include the association :
User.findAll({ include: Company })
I usually create each model using 'class' in different files, but if you need, just include the code below in the #jalex19 solution
companyname:{
type: DataTypes.VIRTUAL,
get() {
return this.Company?.get().name;
},
set(/*value*/) {
throw new Error('Do not try to set the `fullName` value!');
}
},