How do I reset query part with knex.js - node.js

I tried to find anything here in documentation with no success.
What I would like to do is to clone my query builder and reset some query parts like order by or group by. How can I do that ?
It looks like there is no many methods available for this query parts
And there are clear methods only for selects and where conditions.
How do you do it ?
Example:
const qb = knex
.select('id')
.from('table')
.where({ visibility: 'public' })
// some left joins here
.groupBy('id')
How can I do then something like
const new_qb = qb
.clone()
// remove group by here
.clearSelect()
.count()

To reset query part there is a way for example:
this.qb._clearGrouping('order'); // reset order by
this.qb._clearGrouping('group'); // reset group by
and so on.

You can clone the query and add parts to those individual queries.
Like this:
//base query
let query = knex('table_name').where({id: 1});
const countQuery = query.clone().count();
const selectQuery = query.clone().select().limit(10).offset(0);
return Promise.all([countQuery, selectQuery]);

Related

Sequelize WHERE force one condition or not depending on a programmatically condition

I have a bool field in my DB and an endpoint to query that model.
The user sends the bool field is_social_field, if the value is true, I need to force to query only true values, otherwise return it if is true or false.
I managed to do with an OR condition, but I would like to have another solution, this does not seem the best practise. What do you guys think?
const { is_social_field } = req.body;
...
where{
[Op.or]: [{is_social: true}, {is_social: is_social_field}]
}
You can create the query object using the ternary operator like this:
const whereClause = req.body.is_social_field ? {is_sovial:true}:{};
And then use it with spread operator like this in the where clause:
where :
{
...whereClause
}
const { is_social_field } = req.body;
Now you can use the is_social_field to construct the db query. We have 2 scenario's to take care of here.
1. When we need all results irrespective of is_social_field. An appropriate query for that would be without the is_social field.
Like where = {}
2. When we need to filter results based on is_social_field. That query would be where = {is_social: is_social_field}
These two can be achieved via a ternary operator as pointed out in #khopadi's answer
You can also extend object assignment to get rid of the ternary operator too like
const where = {...is_social_field && {is_social:true}}

How to bind array to IN condition with Node postgres

I'm struggling to figure out of to bind an array to an IN query in node pg library.
const env = 'foo';
const sourceTypes = ['one', 'two'];
const resp = await pool.query(
`SELECT source_id, target_id FROM records
WHERE target_env = $1
AND source_type IN ($2)`,
[env, sourceTypes],
);
I've tried several variations and they either error out or don't return any data.
I can make the query when I just use when I manually bind to generate something like this:
SELECT source_id, target_id FROM records
WHERE target_env = 'foo'
AND source_type IN ('one', 'two')
PS: If can provide suggestion on how to actually see the SQL request that PG is generating, that would be extremely helpful!
You can't bind an array to multiple elements of a list in one go. But you can use an array instead of a list by changing in ($2) to =ANY($2)
You can see what queries are getting sent by setting log_statement=all and then viewing the PostgreSQL log file.

Sails.js: How to find records based on values in associated collection?

I'm looking for a way to make sub-query using Sails.js Waterline. The record has an association with Charge model.
I would expect something like that to work, but that doesn't seem to be supported:
var topRecords = await Record.find({'charge.paid':true});
The closest I got was this:
var topRecords = await Record.find().populate('charge',{paid:true});
but the problem is that it still returns all the Records regardless, just doesn't populate the records that do not match populate where statement.
The reason why I can't search for charges first is that I want to sort the data based on one of the values in Record.
You can fetch the Charges then use .map to get the records from there.
const topCharges = await Charge.find({ paid: true }).populate('records');
const topRecords = topCharges.map(charge => charge.record);

Log specific postgresql query using pg-promise

I am using pg-promise package with Nodejs to execute PostgreSQL queries. I want to see the queries executed. Only specific queries, say, just one query that I want to debug.
I can see that one recommended way is to use the pg-monitor to catch the events and log them as mentioned here in the examples documentation.
Without using pg-monitor, is there a simple way to just print the prepared query that is executed. I can't see it in the docs.
Example:
db.query("SELECT * FROM table WHERE id = $/id/", {id: 2})
How to print this query to yield?
SELECT * FROM table WHERE id = 2
is there a simple way to just print the prepared query that is executed...
A query in general - yes, see below. A Prepared Query - no, those are by definition formatted on the server-side.
const query = pgp.as.format('SELECT * FROM table WHERE id = $/id/', {id: 2});
console.log(query);
await db.any(query);
And if you want to print all queries executed by your module, without using pg-monitor, simply add event query handler when initializing the library:
const initOptions = {
query(e) {
console.log(e.query);
}
};
const pgp = require('pg-promise')(initOptions);

breeze: pagination on expand

Is it possible to do the following with Breeze ?
var query = breeze.EntityQuery.from("Mandates").where("Id", "==", mandatId)
.expand("OpenPositions").skip(offset).take(pageSize).inlineCount(true);
I would like the paging to occur on the OpenPositions collection but instead it's applied to the Mandates.
Not sure if this is possible without seeing your schema but why not query on "OpenPositions"? i.e. something like
var query = breeze.EntityQuery.from("OpenPositions")
.where("Mandate.Id", "==", mandatId)
.expand("Mandate").skip(offset).take(pageSize).inlineCount(true);

Resources