Reputation: 951
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
]
})
Upvotes: 17
Views: 24599
Reputation: 3685
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;
}
Upvotes: 3
Reputation: 2775
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
});
Upvotes: 39
Reputation: 16505
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.
Upvotes: -1