Sequlize gives un Wanted info - mysql

i have two tables Products and carts and they are many to many relationship across products_carts table
i am getting specific cart and i am including Product with it so i can get the cart and their products
why i am getting products_carts with the products
my sequlize command:
const a = await Cart.findByPk(1,{
attributes: ['id'],
include: {
model: Product,
attributes: ['id'],
},
});
the sql statement :
Executing (default): SELECT `cart`.`id`, `products`.`id` AS `products.id`,
`products->products_carts`.`createdAt` AS `products.products_carts.createdAt`,
`products->products_carts`.`updatedAt` AS `products.products_carts.updatedAt`,
`products->products_carts`.`cartId` AS `products.products_carts.cartId`, `products-
>products_carts`.`productId` AS `products.products_carts.productId` FROM `carts` AS
`cart` LEFT OUTER JOIN ( `products_carts` AS `products->products_carts` INNER JOIN
`products` AS `products` ON `products`.`id` = `products->products_carts`.`productId`) ON
`cart`.`id` = `products->products_carts`.`cartId` WHERE `cart`.`id` = 1;
the ouput i am getting:
{
"cart": {
"id": 1,
"products": [
{
"id": 1,
"products_carts": { // I DONT WANT THIS TO BE SHOWN !!!
"createdAt": "2022-12-25T13:42:16.000Z",
"updatedAt": "2022-12-25T13:42:16.000Z",
"cartId": 1,
"productId": 1
}
}
]
}
}
the relation between them is ..
Cart.belongsToMany(Product, { through: PC });
Product.belongsToMany(Cart, { through: PC });
User.hasOne(Cart);
Cart.belongsTo(User);
PC stands for products_carts

through: { attributes: [] } worked for me

Related

Count multiple associated models in sequelize

I have 3 models defined, Companies, Projects and Users.
Companies has many Projects and Users, so Projects and users has one company.
The problem that i am facing is when i try to count how many users and projects a company has, i get wrong results, somehow querying multiple associations is modifying the value of each other.
This is the models association:
CompaniesModel.hasMany(AppUsersModel)
AppUsersModel.belongsTo(CompaniesModel)
CompaniesModel.hasMany(ProjectsModel)
ProjectsModel.belongsTo(CompaniesModel)
This is where i try to query the count of Users and Projects for each Company:
const companiesInfo = await models.companies.findAll({
attributes: {
include: [
[sequelize.fn("COUNT", sequelize.col("projects.id")), "projectsCount"],
[sequelize.fn("COUNT", sequelize.col("app_users.id")), "usersCount"],
],
},
include: [
{ model: models.projects, attributes: [] },
{ model: models.app_users, attributes: [] },
],
group: ['companies.id']
})
SQL Query produced:
SELECT `companies`.`id`, COUNT(`projects`.`id`) AS `projectsCount`, COUNT(`app_users`.`id`) AS `usersCount` FROM `companies` AS `companies` LEFT OUTER JOIN `projects` AS `projects` ON `companies`.`id` = `projects`.`companyId` LEFT OUTER JOIN `app_users` AS `app_users` ON `companies`.`id` = `app_users`.`companyId` GROUP BY `companies`.`id`
With this query i expected to get an array of companies like this:
[
{name: companyX, usersCount: 1, projectsCount: 2},
{name: companyY, usersCount: 5, projectsCount: 1},
...
]
But what i am getting is almost what i want but for some reasons the values are being multiplied by each other, for example:
[
{name: companyX, usersCount: 2, projectsCount: 2},
{name: companyY, usersCount: 5, projectsCount: 5},
...
]
This is what i get event though companyX only has 1 user and companyY only has 1 project, but it seems to me that, in the case of companyX, usersCount is being multiplied by projectsCount.
For instance if companyX has 2 users and 2 projects i will get the following results:
[
{name: companyX, usersCount: 4, projectsCount: 4},
...
]
I would be grateful for any insight in to a solution for this.
You need a distinct count if you are counting 2 columns in the same query.
include: [
[sequelize.fn("COUNT", sequelize.fn("DISTINCT", sequelize.col("projects.id"))), "projectsCount"],
[sequelize.fn("COUNT", sequelize.fn("DISTINCT", sequelize.col("app_users.id"))), "usersCount"],
],

SQL json_object producing duplicate values

This is what i need to achieve:
{"id":1,
"work":[
{
"name":"Pied Piper3"
},
{
"name":"Pied Piper"
}
],
"awards":[
{
"title":"Digital Compression Pioneer Award"
}
]}
This is what i am getting
{"id":1,
"work":[
{
"name":"Pied Piper3"
},
{
"name":"Pied Piper"
}
],
"awards":[
{
"title":"Digital Compression Pioneer Award"
},
{
"title":"Digital Compression Pioneer Award"
}
]}
My query:
select json_object('id',basics.resume_id,
'work',JSON_ARRAYAGG(json_object('name', work.name)),
'awards', JSON_ARRAYAGG(JSON_OBJECT('title', awards.title))
) from basics
left join work on basics.resume_id = work.resume_id
left join awards on basics.resume_id = awards.resume_id where basics.resume_id = 1
I have added two rows of work for resume_id = 1 but only 1 row of awards for resume_id = 1.But I still get as many number of awards in result as per the number of works for resume_id =1

Fetch all records from table A where id = somvalue in B plus records which don't have id in B

I have two tables a coupons table and a coupon_city_map table.
id
coupon_code
1
OFFER20
2
OFFER10
3
OFFER50
4
OFFER40
5
OFFER90
coupon_Id
city_id
1
2
2
3
3
4
4
2
I need coupons with ids 1 4, and 5 for city_id = 2.
So It should fetch all the coupons where city_id=2 i.e. coupons with id 1 and 4
and it should also fetch coupons which don't have key in coupon_city_map i.e 5.
This is what I have tried but the query in [Op.or] is not working, and it returns all the coupons instead.
let coupons = await Coupon.findAll({
where: {
[Op.or]: [
{ '$CouponCities.city_id$': city_id },
{ '$CouponCities.coupon_id$': null },
],
...filters // other filter like is_active: true
},
include: {
model: CouponCity,
attributes: [],
},
attributes: ['id', 'coupon_code', 'discount_per', 'flat_discount', 'discount_upto', 'description', 'display'],
});
The query being generated
SELECT `Coupon`.`id`,
`Coupon`.`coupon_code`,
`Coupon`.`discount_per`,
`Coupon`.`flat_discount`,
`Coupon`.`discount_upto`,
`Coupon`.`description`,
`Coupon`.`display`
FROM `coupons` AS `Coupon`
LEFT OUTER JOIN `coupon_city_map` AS `CouponCities` ON `Coupon`.`id` = `CouponCities`.`coupon_id`
WHERE (`Coupon`.`user_id` IS NULL OR `Coupon`.`user_id` = 1)
AND `Coupon`.`is_active` = true
AND `Coupon`.`is_external` = false
AND `Coupon`.`start_date` < '2020-12-30 10:33:20'
AND `Coupon`.`expiry_date` > '2020-12-30 10:33:20';
Update
I also tried below, but still it is returning all the coupons.
let coupons = await Coupon.findAll({
// where: {
// ...filters,
// },
include: {
model: CouponCity,
required: false,
where: {
[Op.or]: [
{
zone_id: zoneId,
}, {
coupon_id: null,
},
],
},
attributes: [],
},
attributes: ['id', 'coupon_code', 'discount_per', 'flat_discount','discount_upto', 'description', 'display'],
});
...and it generates below query.
SELECT `Coupon`.`id`,
`Coupon`.`coupon_code`,
`Coupon`.`discount_per`,
`Coupon`.`flat_discount`,
`Coupon`.`discount_upto`,
`Coupon`.`description`,
`Coupon`.`display`
FROM `coupons` AS `Coupon`
LEFT OUTER JOIN `coupon_city_map` AS `CouponCities`
ON `Coupon`.`id` = `CouponCities`.`coupon_id`
AND ( `CouponCities`.`zone_id` = 1
AND `CouponCities`.`coupon_id` IS NULL )
WHERE `Coupon`.`is_active` = true
AND `Coupon`.`is_external` = false;
This is what worked for me, query is mess but it works. I am posting all the codes for better understanding for anyone interested.
Here zone is city.
{
const filters = {
start_date: {
[Op.lt]: new Date(),
},
expiry_date: {
[Op.gt]: new Date(),
},
};
if (userId) {
filters[Op.or] = [{
user_id: null,
}, {
user_id: userId,
}];
filters[Op.and] = {
[Op.or]: [
sequelize.literal('CouponZones.zone_id = 1'),
sequelize.literal('CouponZones.coupon_id IS null')
],
};
} else {
filters.user_id = null;
}
let coupons = await Coupon.findAll({
where: {
...filters,
},
include: {
model: CouponZone,
attributes: [],
},
attributes: ['id', 'coupon_code', 'discount_per', 'flat_discount', 'discount_upto', 'description', 'display'],
});
This is the query it generates.
SELECT `Coupon`.`id`,
`Coupon`.`coupon_code`,
`Coupon`.`discount_per`,
`Coupon`.`flat_discount`,
`Coupon`.`discount_upto`,
`Coupon`.`description`,
`Coupon`.`display`
FROM `coupons` AS `Coupon`
LEFT OUTER JOIN `coupon_zone_map` AS `CouponZones`
ON `Coupon`.`id` = `CouponZones`.`coupon_id`
WHERE ( `Coupon`.`user_id` IS NULL
OR `Coupon`.`user_id` = 1 )
AND ((CouponZones.zone_id = 1 OR CouponZones.coupon_id IS null))
AND `Coupon`.`is_active` = true
AND `Coupon`.`is_external` = false;
Use UNION
You can write query like below
SELECT coupons.*
FROM coupons,
coupon_city_map
WHERE coupons.id = coupon_city_map.coupon_id
AND coupon_city_map.city_id = 2
UNION
SELECT coupons.*
FROM coupons
WHERE coupons.id NOT IN(SELECT coupon_city_map.coupon_id
FROM coupon_city_map)

Change Alias of Distinct for sequelize

I am using below query on my code that is
await to( mymodel.aggregate('cid', 'DISTINCT', {plain: false,where:{created_by:user.id}}));
and query out put on console is
SELECT DISTINCT(`cid`) AS `DISTINCT` FROM `mymodel` AS `mymodel` WHERE `mymodel`.`created_by` = 7;
I got below output that is
ids --------------- [ { DISTINCT: 9 }, { DISTINCT: 10 }, { DISTINCT: 11 } ]
I want to change the alias that is DISTINCT to id. How i do that like below
ids --------------- [ { id: 9 }, { id: 10 }, { id: 11 } ]
I don't think .aggregate() supports aliasing fields however it's simple to turn this into a regular query instead.
await mymodel.findAll({
attributes: [ [ Sequelize.fn('DISTINCT', 'cid'), 'id' ] ],
where: { created_by: user.id }
});
Here we're utilising Sequelize.fn() to create the DISTINCT on cid and using the array attribute notation to alias it to id. More info on this here.

Unknown column 'Model1->Model2.fieldname' in 'on clause'

I have struggling in this error unknown column error.
I have 3 table the following are
Marketplace --- One to Many relationship (marketplace has many products.)
Product --- One to One relationship (Product belongs to marketplace)
Country -- One to many relationship (Country has many products.)
The sample JSON given below :
[{
"id": 1,
"name": "XYZ Name",
"code": "XYZCODE",
"Products": [
{
"id": 150,
"product_name": "ABC",
"product_location": 19,
"state_id": 24,
"city": "California",
"Country": {
"id": 19,
"name": "USA"
}
},
{
"id": 154,
"product_name": "DEF",
"product_location": 19,
"state_id": 24,
"city": "New York",
"Country": {
"id": 19,
"name": "USA"
}
}
]
}]
If am query city and Country name inside the Country table getting following error in sequelize
{
"code": "ER_BAD_FIELD_ERROR",
"errno": 1054,
"sqlState": "42S22",
"sqlMessage": "Unknown column 'Products->Country.name' in 'on clause'",
"sql": "SELECT `MarketplaceType`.`id`, `MarketplaceType`.`name`, `MarketplaceType`.`code`, `Products`.`id` AS `Products.id`, `Products`.`product_name` AS `Products.product_name`, `Products`.`product_location` AS `Products.product_location`, `Products`.`state_id` AS `Products.state_id`, `Products`.`city` AS `Products.city`, `Products->Country`.`id` AS `Products.Country.id`, `Products->Country`.`name` AS `Products.Country.name` FROM `marketplace_type` AS `MarketplaceType` LEFT OUTER JOIN `product` AS `Products` ON `MarketplaceType`.`id` = `Products`.`marketplace_type_id` AND `Products`.`status` = 1 AND `Products`.`marketplace_id` = 1 AND (`Products`.`city` = 'California' OR `Products->Country`.`name` = 'California') LEFT OUTER JOIN `country` AS `Products->Country` ON `Products`.`product_location` = `Products->Country`.`id` WHERE `MarketplaceType`.`status` = 1 AND `MarketplaceType`.`marketplace_id` = 1;"
}
AND MYSQL Query are following :
SELECT `MarketplaceType`.`id`, `MarketplaceType`.`name`, `MarketplaceType`.`code`, `Products`.`id` AS `Products.id`, `Products`.`product_name` AS `Products.product_name`, `Products`.`product_location` AS `Products.product_location`, `Products`.`state_id` AS `Products.state_id`, `Products`.`city` AS `Products.city`, `Products->Country`.`id` AS `Products.Country.id`, `Products->Country`.`name` AS `Products.Country.name` FROM `marketplace_type` AS `MarketplaceType` LEFT OUTER JOIN `product` AS `Products` ON `MarketplaceType`.`id` = `Products`.`marketplace_type_id` AND `Products`.`status` = 1 AND `Products`.`marketplace_id` = 1 AND (`Products`.`city` = 'California' OR `Products->Country`.`name` = 'California') LEFT OUTER JOIN `country` AS `Products->Country` ON `Products`.`product_location` = `Products->Country`.`id` WHERE `MarketplaceType`.`status` = 1 AND `MarketplaceType`.`marketplace_id` = 1;
ORM Query using sequelize :
var marketplaceTypeQueryObj = {};
var productCountQueryParames = {};
marketplaceTypeQueryObj['status'] = status["ACTIVE"];
marketplaceTypeQueryObj['marketplace_id'] = marketplace['WHOLESALE'];
productCountQueryParames['status'] = status["ACTIVE"];
productCountQueryParames['marketplace_id'] = marketplace['WHOLESALE'];
if (req.query.origin) {
productCountQueryParames['$or'] = [{
city: req.query.origin
}, {
'$Products.Country.name$': req.query.origin
}, {
'$Products.State.name$': req.query.origin
}];
}
console.log('productCountQueryParames', productCountQueryParames);
model['MarketplaceType'].findAll({
where: marketplaceTypeQueryObj,
include: [{
model: model['Product'],
where: productCountQueryParames,
include: [{
model: model['Country'],
attributes: ['id', 'name']
}, {
model: model['State'],
attributes: ['id', 'name']
}],
attributes: ['id', 'product_name', 'product_location', 'state_id', 'city'],
required: false
}],
attributes: ['id', 'name', 'code']
})
Change
attributes: ['id', 'product_name', 'product_location', 'state_id', 'city'],
to
attributes: ['id', 'product_name', 'product_location', 'state_id', 'city','country_id'],
Add country id in your product model attributes