OrmLite Contains() not working as expected - servicestack

If I try to get all users with a certain role like this:
_db.Select<UserAuthCustom>(x => x.Roles.Contains("Bloggers"));
Then it works as expected and returnsthe users.
If I try to do it with the query builder like so:
var q = _db.From<UserAuthCustom>()
.Where(x => x.Roles.Contains("Bloggers"))
.Limit(1);
Then it throws an exception because it thinks "bloggers" is a column and has translated this into into something like WHERE bloggers IN (null).
Is it possible to do something like LIKE '%\"Blogger\"%' on the blobbed field?

You can't use typed queries against blobbed columns like the Roles collection which are blobbed in the table using the configured complex type serializer which defaults to JSV format for all RDBMS's except for PostgreSQL which uses JSON.
If you want to perform server-side queries on the Roles collection I'd recommend persisting them in distinct tables:
container.Register<IAuthRepository>(c =>
new OrmLiteAuthRepository<UserAuthCustom, UserAuthDetails>(c.Resolve<IDbConnectionFactory>()) {
UseDistinctRoleTables = true
});
That way you can use a standard join query to select all users in a specific role:
var q = db.From<UserAuthCustom>()
.Join<UserAuthRole>((u,r) => r.UserAuthId = u.Id)
.Where<UserAuthRole>(x => x.Role == "Bloggers");
Alternatively you would need to create a Custom SQL query to query against the blobbed Roles column as a string, e.g:
q.Where("Roles LIKE #role", new { role = "%Blogger%" });
Or using typed column names in Custom SQL Expressions:
q.Where(q.Column<UserAuthCustom>(x => x.Roles) + " LIKE #role,
new { role = "%Blogger%" });

Related

Is there a way to filter through data based on if a search query is present in the string in mongodb?

I have data that looks like this in my mongoDB atlas database:
object: {
keywords: ['Homelessness', 'Food', 'Poverty']
}
I'm creating a filtering component for my MERN stack website and wanted to add a search feature for keywords like these that are present in each object in the database. If a search query was Homelessness for example, then the object above would show up since it has Homelessness as one of its keywords. But say for example I enter Homeless as a search query, the ones with Homelessness won't pop up because Homeless =/= Homelessness. Is there a way to somehow find if the search query is within a string inside an array which is all inside a json object?
Here is what I tried so far which gets the result I described in the situation above:
const getFilteredProjects = async (req, res) => {
// Initializing request object that will be sent to retrieve DB information
var request = {}
if (req.query.keywords !== '') {
request["keywords"] = req.query.keywords
}
console.log(request)
const projects = await Project.find(request).sort({ assignment_type: 1 })
res.status(200).json(projects)
}
How can I somehow access each string inside the keywords array and see if the search query is present in it? Is that possible with mongodb or would I have to somehow do it through javascript? If that's the case I'm not sure how I could do that, I would appreciate it if I could get some help.

Sequelize case-sensitive queries

I'm using sequelize and want to know, how to send case-sensitive queries to my DB.
I have table users with a column Login.
And when I send request, (data.Login = '***0xwraith***'), sequelize finds me user with login 0xWraith. But I want the logins 0xWraith and 0xwraith be distinct and separate.
This is the code I use:
let db_user = await db.users.findOne({
where: {
Login: data.login
}
});
MySQL's string comparison is case insensitive by default.
If you would like to have case sensitive query just for this query, you can add BINARY keyword before the comparison to enable it.
SELECT * FROM users WHERE BINARY(`Login`) = '0xWraith';
You can write the query in Sequelize as following.
db.users.findOne({
where: sequelize.where(sequelize.fn('BINARY', sequelize.col('Login')), data.login)
})
If you want to enable the case sensitivity as a table level, read more about it here https://dev.mysql.com/doc/refman/8.0/en/case-sensitivity.html.

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 do I reset query part with knex.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]);

How to create a parameterized insert using select query that includes some dynamic values for postgresql?

I am using the nodejs pg package. I have created some simple parameterized queries using the following format:
var client = new Client({user: 'brianc', database: 'test'});
client.on('drain', client.end.bind(client)); //disconnect client when all queries are finished
client.connect();
var query = client.query({
text: 'SELECT name FROM users WHERE email = $1',
values: ['brianc#example.com']
}, function(err, result) {
console.log(result.rows[0].name) // output: brianc
});
But now I have some more complex queries to write where I am creating a copy of a record with a new name and description like the following:
var sNewName = 'new name', sNewDescription = 'new description';
INSERT INTO testtable (
name,
description,
col3name,
col4name,
col5name,
) (
SELECT
sNewName,
sNewDescription,
col3name,
col4name,
col5name
FROM testtable
WHERE
id = 24
) RETURNING *;
On the pg wiki they say the following regarding Parameterized Queries:
A parameterized query allows you "pass arguments" to a query, providing a barrier to SQL injection attacks.
Parameters may not be DDL:
select name from emp where emp_id=$1 – legal
select $1 from emp where emp_id=$2 – illegal – column cannot be parameter
select name from $1 where emp_id=$2 – illegal – table cannot be parameter
select name from $1.emp where emp_id=$2 – illegal – schema cannot be parameter
How then, is it possible to do the above query for copying a record, as a parameterized query?
I am using postgresql 9.5.3 and pg 6.1.2.
Thank your for your time.

Resources