Sequelize -- Use options.distinct with a Where Clause? - postgresql

I'm trying to use Sequelize to find all distinct fields in a column, using a query with a where clause. I've searched the Sequelize docs and tried a number of different things, but haven't yet found the correct syntax.
Here's my current draft syntax:
var searchResults = connectors.cars.findAll({
attributes: [
connectors.Sequelize.options.distinct
],
where: {
condition: connectors.Sequelize.where(connectors.Sequelize.fn('LOWER', connectors.Sequelize.col('mfgr')), 'LIKE', '%' + searchString + '%')
}
});
What is the correct way to use options.distinct alongside a where clause?
Note: edited to remove a bunch of extra code that had been requested in the comments, but which in retrospect may have been obfuscating the issue.

Really more of a comment, but what's going on with this code?
}).then((searchResults) => searchResults.map((item) => item.dataValues));
debugger;
return searchResults; <== ERROR IS THROWN HERE
1) What is the destination of the map()? 2) Won't the return occur before the results are returned, as it's not in the .then() block? Should it not be more like this:
}).then((searchResults) => {
var new_results = searchResults.map((item) => item.dataValues));
debugger;
return new_results;
}
Am I missing something?

I'm getting the impression that this is hard to do in raw sql, let alone Sequelize. I found an answer that uses raw sql here:
const myQuery = "WITH cte AS\n" +
"( SELECT id, mfgr, ROW_NUMBER() OVER (PARTITION BY mfgr ORDER BY mfgr DESC) AS rn\n" +
" FROM cars\n" +
" WHERE LOWER(mfgr) like '%" + searchString + "%'\n" +
")\n" +
"SELECT *\n" +
"FROM cte\n" +
"WHERE rn = 1";
let searchResults = connectors.db.query(myQuery);

Related

Rewrite raw PostgreSQL query to use SelectQueryBuilder from TypeORM

I've written this query that fetches user ids (that's for now, cos I actually need way more fields from the user table as well as from another table called image that is related the user table).
The problem with this query is that it returns a plain object and I need an entity object, I mean I know I could just deserialise it to whatever model I need, but the thing also is that I normally deserialise entity to a required response model. Also, I would like to avoid making
a couple of requests: one fetching user ids and the other fetching right entity objects by those ids using queryBuilder.
So, it seems that one possible solution would be to rewrite this query to make use of queryBuilder straight away.
const matchedUsers = await this.usersRepository.query(
`
SELECT id FROM users
WHERE id IN (
SELECT "usersId" FROM locations_available_fighters_users
WHERE "locationsId" IN (
SELECT "locationsId" FROM locations_available_fighters_users
WHERE "usersId" = ${ me.getId() }
)
) AND is_active IS TRUE
AND id != ${ me.getId() }
AND weight = '${ me.getWeight() }'
AND gender = '${ me.getGender() }'
AND role_name = '${ me.getRoleName() }';
`
);
If the problems you're trying to solve are:
Use a single query
Get the returned data as entity objects rather than raw results
Use QueryBuilder to avoid writing raw queries
I believe what you should be looking into is typeorm subqueries.
For the query you posted in the question, you can try something like below using QueryBuilder:
// Subquery for your inner most subquery,
const locationsQb = connection.getRepository(LocationsAvailableFightersUser)
.createQueryBuilder("lafu_1")
.select("lafu_1.locationsId")
.where("lafu_1.usersId = :usersID", { usersID: me.getId() });
// Subquery for your middle subquery,
const usersQb = connection.getRepository(LocationsAvailableFightersUser)
.createQueryBuilder("lafu_2")
.select("lafu_2.usersId")
.where("lafu_2.locationsId IN (" + locationsQb.getQuery() + ")");
// Query for retrieving `User` entities as you needed,
const matchedUsers = await connection.getRepository(User)
.createQueryBuilder("user")
.where("user.id IN (" + usersQb.getQuery() + ")")
.setParameters(locationsQb.getParameters())
.getMany();
Here I assumed that,
LocationsAvailableFightersUser is the entity for locations_available_fighters_users table
User is the entity for users table
Hope this helps you. Cheers 🍻 !!!

Conditions in prepared statements in postgres

I need to add a condition inside prepared statement in postgres.
Pseudocode (doesn't works, fires an error "argument of WHERE must be type boolean, not type text"):
if (nameFilter) {
whereParam = `name LIKE %${nameFilter}%`
} else {
whereParam = "true"
}
let query = prepare("SELECT * FROM users WHERE $1", whereParam);
Pseudocode (works but looks ugly):
if (nameFilter) {
likeParam = `%${nameFilter}%`
} else {
likeParam = "%"
}
let query = prepare("SELECT * FROM users WHERE name LIKE $1", likeParam);
For some reasons(query is really complex with a bunch of AND) manipulations with a string is not an option, so this will not help
if (nameFilter) {
q = `SELECT * FROM users WHERE name LIKE $1`
} else {
q = "SELECT * FROM users"
}
let query = prepare(q, nameFilter);
Desirable to have statement similar to SELECT * FROM users WHERE $1 AND $2 AND $3 ...
Any suggestions?
This query will work for you.
select * from users where
case
when coalesce($1, '') = '' then true
else (name ~ $1)
end;
The only thing you can pass as a parameter is a constant; you cannot pass part of an SQL query like name LIKE '%pattern%'.
So if your query is really different every time, you have to construct the SQL string in your code, just like you say you cannot do "for some reasons".
It may be annoying, but there is no other way.
When you construct an SQL statement, make sure you never concatenate strings like this:
sql = "SELECT * FROM users WHERE username ='" + username + "'"
because that would be vulnerable to SQL injection.

Error when using "ALL" operator when execute query

I need to execute following query using phalcon framework:
"SELECT id FROM table GROUP BY id HAVING '31' = ALL(array_agg(status))"
How can I execute this query using phalcon?
When I do following:
Model::query()
->columns(['id'])
->groupBy('id')
->having('31 = ALL(array_agg(status))')
->execute();
I get this error message:
Syntax error, unexpected token ALL, near to '(array_agg(status)) ', when parsing: SELECT id FROM [SomeNameSpace\Model] GROUP BY [id] HAVING 31 = ALL(array_agg(status)) (137)
I'm not 100% sure which Postgres functions are supported, but you can try like this:
Model::query()
->columns([
'id',
'ALL(array_agg(status)) AS statusCounter'
])
->groupBy('id')
->having('31 = statusCounter')
->execute();
Notice that I moved the aggregation functions in the select, rather in having clause.
UPDATE: here is an example of very custom query. Most functions used are not supported and it's sometimes cleaner just to write a simple SQL query and bind the desired Model to it:
public static function findNearest($params = null)
{
// A raw SQL statement
$sql = '
SELECT *, 111.045 * DEGREES(ACOS(COS(RADIANS(:lat))
* COS(RADIANS(X(coords)))
* COS(RADIANS(Y(coords)) - RADIANS(:lng))
+ SIN(RADIANS(:lat))
* SIN(RADIANS(X(coords)))))
AS distance_in_km
FROM object_locations
ORDER BY distance_in_km ASC
LIMIT 0,5;
';
// Base model
$model = new ObjectLocations();
// Execute the query
return new \Phalcon\Mvc\Model\Resultset\Simple(
null,
$model,
$model->getReadConnection()->query($sql, $params)
);
}
// How to use:
\Models\ObjectLocations::findNearest([
'lat' => 42.4961756,
'lng' => 27.471543300000008
])
You need to add ALL as dialect extension. Check this topic for example https://forum.phalconphp.com/discussion/16363/where-yearcurrenttimestamp-how-to-do-this

Creating Select statement with variable in single quotes

This relates to taking data from a Google Fusion table.
When I first set up my site, GF tableid was a numeric value, (var tableid = 123456;) and I built a query like this:
layer.setQuery("SELECT 'Latitude' FROM " + tableid + " WHERE 'Name' contains etc etc
Now tableid is something like var tableid = '12DFty24'; and I'm having trouble converting the setQuery to handle it.
I've tried adding an extra single quote around tableid, but that doesn't work. Nor do backslashes.
Ideas would be gratefully received!
Paul
You are using the old syntax that can't work with encrypted ID, numeric ID's are deprecated.
You have to change your code using the new syntax; here is the documentation
Example:
new google.maps.FusionTablesLayer({ query: {[FusionTablesQuery object]}});
And here's the one that works...need to be careful with parentheses and commas!
function searchAddress()
{
var searchString = document.getElementById('searchAddressString').value.replace("'", "\\'");
// layer.setQuery("SELECT 'Latitude' FROM " + tableid + " WHERE 'Address' contains ignoring case '" + searchString + "'");
var layer = new google.maps.FusionTablesLayer({
query: {
select: 'Latitude',
from: tableid,
where: 'Address' contains ignoring case '" + searchString + "'"
}
});
layer.setMap(map);
}

How to Convert FQL Result to List of Records.?

I want to Convert my FQL Query result into the List of Records how I can Convert this my Query like this.
"SELECT comments FROM stream WHERE post_id = 'Post_Id' "
I have converted into foreach loop but it will still not get desired result so my question is I want to list of comments of Post.?
Use http://developers.facebook.com/docs/reference/javascript/FB.api/
FB.api({
method: 'fql.query',
query: 'SELECT comments FROM stream WHERE post_id=\'' + POST_ID + '\''
}, function(response) {
alert(response.length);
if(response.length!=1) return; // bail out, no stream item found
var comment_list = response[0].commment_list;
for(var i=0; i<response[0].count; i++) {
console.dir(comment_list[i]);
alert('from: ' + comment_list[i].fromid + ' text: ' + comment_list[i].text);
}
}
);
You can try it out for yourself at http://developers.facebook.com/tools/console/. Just click on Examples and select "everyone-data" and change the query to be your SELECT, and then play with the code.