Sequelize Parens in WHERE Clause - sql

I have a WHERE clause that looks like this.
WHERE (`version` = FALSE
OR (name LIKE '%8%')
OR (name LIKE '%9%')
AND (sId IN (1)))
I need it to look like this.
WHERE (`version` = FALSE
OR (name LIKE '%8%')
OR (name LIKE '%9%'))
AND (sId IN (1))
I'm using where.push and I can't seem to figure it out.
Sequelize code.
where.push(version: false)
where.push(Sequelize.literal(`OR (name LIKE '%${id1}%')`)
where.push(Sequelize.literal(`OR (name LIKE '%${id2}%')`)
where.push({sId: {$in: sIds}})

Don't use Sequelize.literal (and definitely don't try to compose such conditions yourself in a string to avoid SQL injections) if you can write such conditions using some Op operators.
In your case you can use Op.or and Op.like operators:
where = {
[Op.or]: [{
version: false,
}, {
name: {
[Op.like]: `%${id1}%`
}
}, {
name: {
[Op.like]: `%${id2}%`
}
},
],
sId: {
[Op.in]: sIds
}
}

Related

Ordering nested / second level Arrays with Prisma?

I am using Prisma & PostgreSQL. Here I grab some stuff:
await prisma.items.findMany({
where: { itemId: itemId },
include: {
modules: {
include: {
lessons: true
}
}
}
});
I do not need to order the items themselves, but I would like to order the modules & lessons that I get back. Both have an INT property (called: number) on which I could perform the ordering, but I do not know how to do this with prisma / postgresql, or even if it's possible.
Any ideas?
You can use the orderBy operator for this.
Here's what the query would look like for your use-case:
const data = await prisma.items.findMany({
where: {itemId: itemId},
include: {
modules: {
orderBy: {
number: 'asc'
},
include: {
lessons: {
orderBy: {
number: 'asc'
}
}
}
}
}
})
The article on filtering and sorting contains more information on this.

Sequelize allownull constraint conditionally

I need a migration in sequelize to change a column. How can I use allowNull constraint on a column based on the value of another column?
For example consider I have columns A and B. In the migration I wanna have something like below:
queryInterface.changeColumn('book', ['A'], {
allowNull: false,
where: { B: true }
});
But as I see in the examples, we can't use 'where' in changeColumn.
I think you must use customValidator for this problem like this :
queryInterface.changeColumn('book', ['A'], {
allowNull: true,
validate: {
customValidator(value) {
if (value === null && this.B) {
throw new Error("A not be null if B === true");
}
}
}
});

Why is Date query with aggregate is not working in parse-server?

I want to query user where updatedAt is less than or equal today using aggregate because I'm doing other stuff like sorting by pointers.
I'm using cloud code to define the query from the server.
I first tried using mongoDB Compass to check my query using ISODate and it works, but using it in NodeJS seems not working correctly.
I also noticed about this problem that was already fix, they say. I also saw their tests.
Here's a link to that PR.
I'm passing date like this:
const pipeline = [
{
project: {
_id: true,
process: {
$substr: ['$_p_testdata', 12, -1]
}
}
},
{
lookup: {
from: 'Test',
localField: 'process',
foreignField: '_id',
as: 'process'
}
},
{
unwind: {
path: '$process'
}
},
{
match: {
'process._updated_at': {
$lte: new Date()
}
}
}
];
const query = new Parse.Query('data');
return query.aggregate(pipeline);
I expect value to be an array with length of 4 but only give me empty array.
I was able to fetch data without match date.
Please try this:
const pipeline = [
{
match: {
'editedBy.updatedAt': {
$lte: new Date()
}
}
}
];

How to perform a search with conditional where parameters using Sequelize

Usually whenever I write a search query for SQL, I do something similar to this:
SELECT * FROM users u
WHERE (#username IS NULL OR u.username like '%' + #username + '%')
AND (#id IS NULL OR u.id = #id)
Basically this simulates a conditional WHERE clause. We only want to compare #searchParam to the column if #searchParam was provided.
Is there a way to replicate this using Sequelize?
EDIT: Here is my best attempt which fails:
models.user.findAll({
where: {
username: searchParams.username || models.sequelize.col('user.username'),
id: searchParams.id || models.sequelize.col('user.id')
}
})
UPDATE: I found a way to do it, but it feels like a workaround. I'm certain there has to be a more elegant way. This works, but is ugly:
models.user.findAll({
where: [
'(? IS NULL OR "user"."username" LIKE ?) AND (? IS NULL OR "user"."id" = ?)',
searchParams.username,
`%${searchParams.username}%`,
searchParams.id,
searchParams.id
]
})
You can just prepare object with needed conditions. Simple and easy to understand
var whereStatement = {};
if(searchParams.id)
whereStatement.id = searchParams.id;
if(searchParams.username)
whereStatement.username = {$like: '%' + searchParams.username + '%'};
models.user.findAll({
where: whereStatement
});
that's pretty awesome. thank you. i use your ideas like that:
app.get('/', function (req, res) {
..
let foo = await Foo.findAll(
{
offset: parseInt(req.query.offset | 0),
limit: parseInt(req.query.limit | 10),
where: getFooConditions(req),
...
}
function getFooConditions(req) {
fooConditions = {};
// Query param date
if (req.query.date) {
fooCondtions.start = {
[Op.gte]: moment(parseInt(req.query.date)).utc().startOf('day'),
[Op.lte]: moment(parseInt(req.query.date)).utc().endOf('day')
}
}
// Query param name
if (req.query.name) {
fooCondtions.name = {
[Op.like]: '%' + (req.query.name) + '%'
}
}
// Query param id
if (req.query.id) {
fooCondtions.id = {
[Op.equals]: '%' + (req.query.id) + '%'
}
}
return fooConditions;
}
It'd be a little more complicated than you've outlined above. Sequelize has to have pretty explicit statements on ands and ors, and that means you have to use the $and and $or options to replicate what you're looking for. What you've done above is merely create the values in JavaScript and pass them to the database. Try the following:
models.user.findAll({
where: {
$and: [{
$or: [{
username: {
$like: '%' + searchParams.username '%'
}
}, {
username: null
}]
}, {
$or: [{
id: searchParams.id
}, {
id: null
}]
}]
}
})
For more on this, and some good examples, see their documentation.

How to pass function in sql query of DocumentDB for NodeJS?

Q.1: I want to run one query on DocumentDB with user defined function,
var udf = function(users, userid) {
var s, _i, _len;
for (_i = 0, _len = users.length; _i < _len; _i++) {
s = users[_i];
if (s.userid === userid) {
return true;
}
}
return false;
};
conversationsQuerySpec = {
query: 'SELECT * FROM root r WHERE #fn(r.users, #userid) AND r.id=#id',
parameters: [{
name: '#fn',
value: udf
}, {
name: '#userid',
value: userid
}, {
name: '#id',
value: id
}]
};
But problem is that this query is not running throwing error.
Q.2: I have 1 object in documentDB with array like:
var student = {
name: 'piyush',
classes: [{
level: '1st',
medium: 'spanish'
},{
level: '2nd',
medium: 'german'
}]
}
I want to run query where medium=german, I don't want to pass level=2nd, how can I run this query?
Q1. You have to upload the UDF independently rather than as a parameter. Just upsert it using the appropriate SDK call before running that query.
First to register the UDF using createUserDefinedFunction within the collection with a name like myUserDefinedFunction.
Then you can use it inside the query by name, e.g. SELECT * FROM root r WHERE udf.myUserDefinedFunction(r.users, #userid) AND r.id=#id
Q2. This should work (untested):
SELECT VALUE student FROM student JOIN c in student.classes WHERE c.medium = "german"