Return updated values from sequelize raw query - postgresql

I have an operation that uses a raw query to update the database, i'd like to get the rows affected by the query as the output. Is this possible?
const op = (replacements, pgdb) {
const query = q(replacements);
const args = [query, { replacements, type: Sequelize.QueryTypes.UPDATE, raw: true }];
const results = await pgdb.query(...args);
console.log(results);
return results;
};

Postgresql can return records with RETURNING.
UPDATE T
SET ...
WHERE ...
RETURNING *

Yes you can. I'm using Sequelize with a PostgreSQL database. My specs are as follows:
"pg": "^7.12.1"
"sequelize": "^5.21.2"
"sequelize-cli": "^5.5.1"
I ran an update query in the following code block:
const query = `UPDATE bookings b
SET "isPaid" = :isPaid,
"paymentType" = :paymentType
FROM trips t,
requests r
WHERE "b"."tripId" = t.id
AND r.id = "t"."requestId"
AND r.id = :requestId
AND "r"."userId" = :userId
RETURNING b.id, "isPaid", "paymentType"`;
return db.sequelize.query(
query, {
replacements: {
isPaid, paymentType, requestId, userId
}
}
);
I logged the result:
console.log('resultFromQuery', resultFromQuery);
and got the following:
resultFromQuery [
[
{ id: 7, isPaid: true, paymentType: 'paypal' },
{ id: 8, isPaid: true, paymentType: 'paypal' }
],
Result {
command: 'UPDATE',
rowCount: 2,
oid: null,
rows: [ [Object], [Object] ],
fields: [ [Field], [Field], [Field] ],
_parsers: [ [Function: parser], [Function: parser], [Function: parser] ],
_types: TypeOverrides { _types: [Object], text: {}, binary: {} },
RowCtor: null,
rowAsArray: false
}
]
I was then able to get the rowCount as follows:
console.log('resultFromQuery', resultFromQuery[1].rowCount);
I was also able to get the updated rows themselves as follows (you can select the entire row like you did with '*' or specify the fields you want):
console.log('resultFromQuery', resultFromQuery[0]);

Related

Prisma, Can't use '_count' in 'FindMany' query to get total count of the data

const fictions = await client.fiction.findMany({
**_count: true,**
take: 18,
skip: (+page!.toString() - 1 || 0) * 18,
where: {
AND: [
{ OR: [...genresMany] },
{
OR: [...nationalitiesMany],
},
{
AND: [...keywordMany],
},
],
},
include: {
_count: {
select: {
favs: true,
},
},
author: true,
},
...sortingOne(),
});
I'd like to get total count of the query for pagination. And the manual says the using _count is the way.
However, it seems _count cannot be used in the query, and I can't find out the reason.
Is it a wrong usage?
If it's wrong, then what can I do for getting the total count of the query (not 18, the taked items)?
Should I count them again with the similar code after the query? I think that's too wasteful.
Would be very thanks if there's any help.
there should be a top-level count method for your model. You could that first to just return a count, that request should be fast and cheap since it has to do no sorting / fetching of data. And then you can do a separate call to actually return data and paginate through it.
const fictions = await client.fiction.count({
where: {
AND: [
{ OR: [...genresMany] },
{
OR: [...nationalitiesMany],
},
{
AND: [...keywordMany],
},
],
}
});

why finding a record using objectId without await returns something else;

**Any one know about this ?? **
This is my code , I want to know why it gives output like these
if(orderItem != null){
// orderItem = []
orderItem.forEach( async data => {
productData = await AdminDB.findById({_id: data.orderedItemId}) ; // here data.orderedItemId contains objectId as string
console.log(productData);
});
}
Without await
Query {
_mongooseOptions: {},
_transforms: [],
_hooks: Kareem { _pres: Map(0) {}, _posts: Map(0) {} },
_executionStack: null,
mongooseCollection: Collection {
strictQuery: true,
strict: true,
pluralization: true
}, ** etc. etc ...and something like these**
with await
{
_id: new ObjectId("62af22d10cb99b48652d5d62"),
category: 'ghee',
quantity: '5',
amount: '12000',
productimg: 'https://images.pexels.com/photos/12447940/pexels-photo-12447940.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1',
__v: 0
} ** which returns record **

Sequelize: Returning a single COUNT entry instead of every row in a nested include

I'm trying to grab the total number of rows (count) from a nested include in Sequelize. I've followed countless questions on here, but can't seem to get it right.
Models:
Brand
BrandProfile (alias: brand_profile)
BrandPageView (alias brand_page_view)
Relationships:
// Brand
Brand.hasOne(models.BrandProfile, {
foreignKey: 'brand_id',
as: 'brand_profile'
})
// BrandProfile
BrandProfile.belongsTo(models.Brand, {
foreignKey: 'brand_id',
})
BrandProfile.hasMany(models.BrandPageView, {
foreignKey: 'brand_id',
as: 'brand_page_views'
})
// BrandPageView
BrandProfile.belongsTo(models.BrandProfile, {
foreignKey: 'brand_id',
})
Now when I try to normally run my query like so:
const { count, rows } = await Brand.findAndCountAll({
include: [
{
model: BrandProfile,
as: 'brand_profile',
include: [
{
model: BrandPageView,
as: 'brand_page_views',
},
],
},
],
})
It returns the following:
{
id: 1,
created_at: '2020-12-26T20:42:19.930Z',
updated_at: '2020-12-29T20:46:58.918Z',
deleted_at: null,
name: 'Test brand',
slug: 'test-brand',
status: 'disabled',
brand_profile: {
created_at: '2020-12-26T20:42:19.931Z',
about: [ [Object], [Object], [Object], [Object] ],
cleaned_about: null,
subtitle: 'subtitle test',
photo: '1609477287152.jpeg',
photo_config: { scale: '1.00' },
id: 1,
updated_at: '2021-01-01T05:01:27.414Z',
brand_id: 1,
brand_page_views: [
[Object], [Object],
[Object], [Object],
[Object], [Object],
[Object]
]
},
}
As you can see, brand.brand_profile.brand_page_views has a list of all objects. Now I just want to return the count, so I'm using the following query:
const { count, rows } = await Brand.findAndCountAll({
include: [
{
model: BrandProfile,
as: 'brand_profile',
include: {
model: BrandPageView,
as: 'brand_page_views',
attributes: [],
},
},
],
attributes: {
include: [
[
Sequelize.fn('COUNT', Sequelize.col('brand_profile.brand_page_views.brand_id')),
'brand_page_views_count',
],
],
},
group: ['brand.id']
})
I get this error:
'missing FROM-clause entry for table "brand"'
The SQL it outputs is:
SELECT "Brand"."id", "Brand"."created_at", "Brand"."updated_at", "Brand"."deleted_at", "Brand"."name", "Brand"."slug", "Brand"."status", COUNT("brand_profile->brand_page_views"."brand_id") AS "brand_profile.brand_page_views.count", "brand_profile"."created_at" AS "brand_profile.created_at", "brand_profile"."about" AS "brand_profile.about", "brand_profile"."cleaned_about" AS "brand_profile.cleaned_about", "brand_profile"."subtitle" AS "brand_profile.subtitle", "brand_profile"."photo" AS "brand_profile.photo", "brand_profile"."email" AS "brand_profile.email", "brand_profile"."photo_config" AS "brand_profile.photo_config", "brand_profile"."id" AS "brand_profile.id", "brand_profile"."updated_at" AS "brand_profile.updated_at", "brand_profile"."brand_id" AS "brand_profile.brand_id" FROM "brands" AS "Brand" LEFT OUTER JOIN "brand_profile" AS "brand_profile" ON "Br2021-01-05 01:32:26 [sequelize] INFO Executing (default): SELECT "Brand"."id", "Brand"."created_at", "Brand"."updated_at", "Brand"."deleted_at", "Brand"."name", "Brand"."slug", "Brand"."status", COUNT("brand_profile->brand_page_views"."brand_id") AS "brand_profile.brand_page_views.count", "brand_profile"."created_at" AS "brand_profile.created_at", "brand_profile"."about" AS "brand_profile.about", "brand_profile"."cleaned_about" AS "brand_profile.cleaned_about", "brand_profile"."subtitle" AS "brand_profile.subtitle", "brand_profile"."photo" AS "brand_profile.photo", "brand_profile"."email" AS "brand_profile.email", "brand_profile"."photo_config" AS "brand_profile.photo_config", "brand_profile"."id" AS "brand_profile.id", "brand_profile"."updated_at" AS "brand_profile.updated_at", "brand_profile"."brand_id" AS "brand_profile.brand_id" FROM "brands" AS "Brand" LEFT OUTER JOIN "brand_profile" AS "brand_profile" ON "Brand"."id" = "brand_profile"."brand_id" LEFT OUTER JOIN "brand_page_views" AS "brand_profile->braand"."id" = "brand_profile"."brand_id" LEFT OUTER JOIN "brand_page_views" AS "brand_profile->brand_page_views" ON "brand_profile"."id" = "brand_profile->brand_page_views"."brand_id" WHERE "Brand"."id" = 1 GROUP BY "brand"."id";
nd_page_views" ON "brand_profile"."id" = "brand_profile->brand_page_views"."brand_id" WHERE "Brand"."id" = 1 GROUP BY "brand"."id";
I've honestly tried this so many ways, added brand_profile->brand_page_views.brand_id, brand_profile.brand_id to the group, but to no avail.
Sequelize was not designed to support a wide variety of SQL aggregations. So in your case you should use sequelize.literal with a subquery to count child records:
attributes: {
include: [
[Sequelize.literal('(select COUNT(*) from brand_page_views where brand_page_views.brand_id=brand_profile.id)'),
'brand_page_views_count'],
],
},
Don't forget to remove group: ['brand.id']

Use included Models in Where Statements with Sequelize

I am using Sequelize 4.38.0, with Postgres. I am trying to implement a search feature. But I am having trouble validating the query. I have to check if the query matches a city. It doesn't have to necessarily match.
I want to move the query to the City Model to the top level WHERE like described here: http://docs.sequelizejs.com/manual/tutorial/models-usage.html#top-level-where-with-eagerly-loaded-models But I get this error: Unhandled rejection SequelizeDatabaseError: missing an entry for the "City" table in the FROM clause
Model Definition
const Property = sequelize.define('property', {
id: {
type: type.STRING,
unique: true,
allowNull: false,
primaryKey: true
},
name: {
type: type.STRING,
allowNull: false
},
// ...
isVisible: {
type: type.BOOLEAN,
default: false
}
});
const City = sequelize.define('city', {
name: {
type: type.STRING
},
}, {
timestamps: false,
});
The Query
sequelize.sync().then(() => {
let query = 'new';
let whereStatement = {
$or: [{
name: {
$ilike: '%' + query + '%'
}
},
{
description: {
$ilike: '%' + query + '%'
}
},
// I get the Error if I uncomment this
// {
// '$City.name$': {
// $ilike: '%' + query + '%'
// }
// }
]
};
Property.findAndCountAll({
where: whereStatement,
include: [{
model: City,
where: {
name: {
$ilike: '%' + query + '%'
}
}
// I want to move this where to the upper level
// where inside the OR opertator
},
{
model: Photo
}
],
distinct: true,
order: [
['createdAt', 'DESC']
]
}).then(properties => {
console.log(properties.count)
});
});
The Actual Query has a bit more attributes. The resultant SQL is:
Executing (default): SELECT "property".*, "city"."id" AS "city.id", "city"."name" AS "city.name", "city"."provinceId" AS "city.provinceId", "photos"."id" AS "photos.id", "photos"."location" AS "photos.location", "photos"."slug" AS "photos.slug", "photos"."description" AS "photos.description", "photos"."isPrimary" AS "photos.isPrimary", "photos"."createdAt" AS "photos.createdAt", "photos"."updatedAt" AS "photos.updatedAt", "photos"."propertyId" AS "photos.propertyId" FROM (SELECT "property"."id", "property"."webSlug", "property"."name", "property"."description", "property"."direction", "property"."price", "property"."areaConstruction", "property"."areaLot", "property"."isVisible", "property"."isAvailable", "property"."isNegociable", "property"."isRural", "property"."latitude", "property"."longitude", "property"."map_radio", "property"."video_url", "property"."createdAt", "property"."updatedAt", "property"."cityId", "property"."propertyTypeId" FROM "properties" AS "property" WHERE ("property"."name" ILIKE '%My Query%' OR "property"."description" ILIKE '%My Query%' OR "property"."id" ILIKE '%My Query%' OR "properties_city"."name" ILIKE '%My Query%') AND "property"."isVisible" = true ORDER BY "property"."createdAt" DESC LIMIT 10 OFFSET 0) AS "property" LEFT OUTER JOIN "cities" AS "city" ON "property"."cityId" = "city"."id" LEFT OUTER JOIN "photos" AS "photos" ON "property"."id" = "photos"."propertyId" ORDER BY "property"."createdAt" DESC;
Update
If I use the same Models and same whereStatement but i change the findAndCountAll() function to a findAll() the search feature works propertly and I can add the '$city.name$': { $ilike: '%' + query + '%' } to the upper WHERE.
Property.findAll({
where: whereStatement,
include: [{model: City}, {model: Photo}],
distinct: true,
order: [['createdAt', 'DESC']],
}).then(properties => {
res.render('search', {
title: 'Buscar',
properties: properties,
query: query,
propertyTypeId: propertyTypeId,
propertyTypes: req.propertyTypes,
})
})
The SQL output:
Executing (default): SELECT "property"."id", "property"."webSlug", "property"."name", "property"."description", "property"."direction", "property"."price", "property"."areaConstruction", "property"."areaLot", "property"."isVisible", "property"."isAvailable", "property"."isNegociable", "property"."isRural", "property"."latitude", "property"."longitude", "property"."map_radio", "property"."video_url", "property"."createdAt", "property"."updatedAt", "property"."cityId", "property"."propertyTypeId", "city"."id" AS "city.id", "city"."name" AS "city.name", "city"."provinceId" AS "city.provinceId", "photos"."id" AS "photos.id", "photos"."location" AS "photos.location", "photos"."slug" AS "photos.slug", "photos"."description" AS "photos.description", "photos"."isPrimary" AS "photos.isPrimary", "photos"."createdAt" AS "photos.createdAt", "photos"."updatedAt" AS "photos.updatedAt", "photos"."propertyId" AS "photos.propertyId" FROM "properties" AS "property" LEFT OUTER JOIN "cities" AS "city" ON "property"."cityId" = "city"."id" LEFT OUTER JOIN "photos" AS "photos" ON "property"."id" = "photos"."propertyId" WHERE ("property"."name" ILIKE '%City_Query%' OR "property"."description" ILIKE '%City_Query%' OR "property"."id" ILIKE '%City_Query%' OR "city"."name" ILIKE '%City_Query%') AND "property"."isVisible" = true ORDER BY "property"."createdAt" DESC;
Try this it should work. include
"duplicating":false
in this
sequelize.sync().then(() => {
let query = 'new';
let whereStatement = {
$or: [{
name: {
$ilike: '%' + query + '%'
}
},
{
description: {
$ilike: '%' + query + '%'
}
},
{
'$City.name$': {
$ilike: '%' + query + '%'
}
}
]
};
Property.findAndCountAll({
where: whereStatement,
include: [{
model: City,
attributes: [],
duplicating:false
},
{
model: Photo
}
],
distinct: true,
order: [
['createdAt', 'DESC']
]
}).then(properties => {
console.log(properties.count)
});
});

Sequelize Group By Returns Not All Attributes

I am trying to write a query to returns everything that a device has.
Currently my query is:
var getHardwareData = function() {
return Device.findAll({
where: {
ownerId: req.account.id
},
attributes: [
'"hardwareName"',
[Sequelize.fn('COUNT', '*'), 'count'],
],
group: '"hardwareName"',
}).then(function(devices) {
return devices;
});
};
I want to have hardwareName and the count of it. Currently it returns count: 1 and only it.