Where query with "internal relation" of the searched object - node.js

I would like to use sequelize in order to produce simple query, kind of:
SELECT * FROM `Products`
WHERE `Product`.`oldPrice` > `Product`.`newPrice`
At the moment I do kind of ugly raw query, like:
database.Product.find({ where: '`Product`.`oldPrice` > `Product`.`newPrice`' })
It is not really bad practice or something, but I wonder whether I have not missed a paragraph amidst the documentation which would introduce me to a cleaner form, like for example mongo function expression (see: http://mongoosejs.com/docs/api.html#query_Query-%24where).
database.Product.find({ where: function () {
return (this.oldPrice > this.newPrice);
});
Is there a shortcut of such kind, or will I have to keep on writing SQL in such cases?
Thanks in advance.

Product.find({
where: {
oldPrice: {
gt: sequelize.col('newPrice')
}
}
});

Related

Search string value inside an array of objects inside an object of the jsonb column- TypeORM and Nest.js

the problem I am facing is as follows:
Search value: 'cooking'
JSON object::
data: {
skills: {
items: [ { name: 'cooking' }, ... ]
}
}
Expected result: Should find all the "skill items" that contain 'cooking' inside their name, using TypeORM and Nest.js.
The current code does not support search on the backend, and I should implement this. I want to use TypeORM features, rather than handling it with JavaScript.
Current code: (returns data based on the userId)
const allItems = this.dataRepository.find({ where: [{ user: { id: userId } }] })
I investigated the PostgreSQL documentation regarding the PostgreSQL functions and even though I understand how to create a raw SQL query, I am struggling to convert this to the TypeORM equivalent.
Note: I researched many StackOverflow issues before creating this question, but do inform me If I missed the right one. I will be glad to investigate.
Can you help me figure out the way to query this with TypeORM?
UPDATE
Let's consider the simple raw query:
SELECT *
FROM table1 t
WHERE t.data->'skills' #> '{"items":[{ "name": "cooking"}]}';
This query will provide the result for any item within the items array that will match exact name - in this case, "cooking".
That's totally fine, and it can be executed as a raw request but it is certainly not easy to maintain in the future, nor to use pattern matching and wildcards (I couldn't find a solution to do that, If you know how to do it please share!). But, this solution is good enough when you have to work on the exact matches. I'll keep this question updated with the new findings.
use Like in Where clause:
servicePoint = await this.servicePointAddressRepository.find({
where: [{ ...isActive, name: Like("%"+key+"%"), serviceExecutive:{id: userId} },
{ ...isActive, servicePointId: Like("%"+key+"%")},
{ ...isActive, branchCode: Like("%"+key+"%")},
],
skip: (page - 1) * limit,
take: limit,
order: { updatedAt: "DESC" },
relations:["serviceExecutive","address"]
});
This may help you! I'm matching with key here.

Loopback 4: Filter option

Loopback 4 allows to use an automatic/default filter that is really helpfull. My problem is that I want to use it in a customize way an I am not able.
Usual:
return this.customerRepository.findById(idCustomer, filter);
My Case:
I donĀ“t want to attack the "id" of the model, I want to attack another field. I have tried serveral things, but as a resume an example:
return this.customerRepository.findOne({where: { idUser: currentUserProfile.id }}, filter));
If I do that, the filter stop working. Any idea of how to mix a field in the model different than the id and the filter of loopback 4?
Thanks in advance
Best regards
#Jota what do you mean the filter stopped working? You have the correct idea about the approach. to search by a specific field just put it in the where clause as such:
this.customerRepository.findOne({ where: { <field_name>: <value_to_search> } })
e.g.
const filter = {
where: {
email: 'hello#world.com'
}
};
const result = await this.customerRepository.findOne(filter);

Postgres Node search query using LIKE, how to set %

I have a weird problem I encountered using Postgresql and Node. I would like to use LIKE in my query together with % at the beginning and end of searched term. I have no issue using it in the plain SQL:
THIS WORKS:
SELECT * FROM vehicle WHERE module_imei LIKE '%searchterm%' OR custom_id LIKE '%searchterm%'
However, using it in Node is a bit of challenge. I haven't been successful in resolving it yet:
THIS DOES NOT WORK:
getVehiclesSearch: async function({ search }) {
let response;
try {
response = await pool.query(`SELECT * FROM vehicle WHERE module_imei LIKE %$1% OR custom_id LIKE %$1%`, [search]);
if(response) return response.rows;
} catch(error) {
// handle error
console.error(error);
// do not throw anything
}
},
Doing above will produce: syntax error at or near "%"
SELECT * FROM vehicle WHERE module_imei LIKE '%${$1}%' OR custom_id LIKE '%${$1}%
Doing above will produce: $1 is not defined
SELECT * FROM vehicle WHERE module_imei LIKE '%$1%' OR custom_id LIKE '%$1%'
Doing above will produce: bind message supplies 1 parameters, but prepared statement "" requires 0
I kind of struggle factoring the % in so it won't crash the query. Simply run out of ideas after trying above and variables of those. Thanks for your kind help.
This has been already answered over here:
Go postgresql LIKE query
In this particular case:
response = await pool.query(`SELECT * FROM vehicle WHERE module_imei LIKE '%'||$1||'%' OR custom_id LIKE '%'||$1||'%'`, [search]);
This would work.
You are missing single quotes, also I don't recognize a db adapter you use, but you can use template literals (watch out for sql injection!!!)
response = await pool.query(`SELECT * FROM vehicle WHERE module_imei LIKE '%${search}%' OR custom_id LIKE '%${search}%'`);

Mongoose display comments and stars(likes) for each post [duplicate]

In Mongoose, I can use a query populate to populate additional fields after a query. I can also populate multiple paths, such as
Person.find({})
.populate('books movie', 'title pages director')
.exec()
However, this would generate a lookup on book gathering the fields for title, pages and director - and also a lookup on movie gathering the fields for title, pages and director as well. What I want is to get title and pages from books only, and director from movie. I could do something like this:
Person.find({})
.populate('books', 'title pages')
.populate('movie', 'director')
.exec()
which gives me the expected result and queries.
But is there any way to have the behavior of the second snippet using a similar "single line" syntax like the first snippet? The reason for that, is that I want to programmatically determine the arguments for the populate function and feed it in. I cannot do that for multiple populate calls.
After looking into the sourcecode of mongoose, I solved this with:
var populateQuery = [{path:'books', select:'title pages'}, {path:'movie', select:'director'}];
Person.find({})
.populate(populateQuery)
.execPopulate()
you can also do something like below:
{path:'user',select:['key1','key2']}
You achieve that by simply passing object or array of objects to populate() method.
const query = [
{
path:'books',
select:'title pages'
},
{
path:'movie',
select:'director'
}
];
const result = await Person.find().populate(query).lean();
Consider that lean() method is optional, it just returns raw json rather than mongoose object and makes code execution a little bit faster! Don't forget to make your function (callback) async!
This is how it's done based on the Mongoose JS documentation http://mongoosejs.com/docs/populate.html
Let's say you have a BookCollection schema which contains users and books
In order to perform a query and get all the BookCollections with its related users and books you would do this
models.BookCollection
.find({})
.populate('user')
.populate('books')
.lean()
.exec(function (err, bookcollection) {
if (err) return console.error(err);
try {
mongoose.connection.close();
res.render('viewbookcollection', { content: bookcollection});
} catch (e) {
console.log("errror getting bookcollection"+e);
}
//Your Schema must include path
let createdData =Person.create(dataYouWant)
await createdData.populate([{path:'books', select:'title pages'},{path:'movie', select:'director'}])

Is it possible to disable automatic type casting for Mongoose SchemaTypes?

For a model with this Schema...
{
name: { type: String }
}
...the following automatically casts the provided value to a string instead of enforcing the type:
document.name = 2;
document.validate(err => {
// Err is null, document.name === '2'
})
Is there a simple way to disable this behaviour?
Just in case anyone else stumbles upon this, it looks like mongoose will be supporting this according to this issue.
you can use lean() method with your find/findOne queries.
lean() will remove all the effect a mongoose schema has, i.e. it will return data as it is saved in MongoDB without any typecasting.
Note:- After using lean() you will not be able to call update or save on that returned data.
Also, this will increase your query performance.
example
Model.find().lean().exec((err, result) => {
console.log(result); //data without any typecasting
/*some operations on result*/
result.save(); // this will not work
});

Resources