allen
allen17mo ago

conditional filter

Is there a way to conditionally filter a query? It doesn't seem possible to break up the chaining conditionally, and it also doesn't seem possible to exit early from the .filter(...) function. Id rather not write out the entire query chain multiple times for each condition, as this is the only part of the query that changes.
15 Replies
lee
lee17mo ago
.filter(q => true) is a no-op filter. but also note you can do whatever filters and post-processing you want in javascript after getting results, and it's very similar under the hood (because the js code is running on the server, just like the filter), so i would recommend that over complicated filters to answer your question though, i think the syntax for a the conditional filter would be like .filter((q) => { if (conditional) { return q.eq(...filter...) } else { return true }})
allen
allenOP17mo ago
@Lee its a paginated query, so doing js based filtering is not ideal. Thanks for the escape noop syntax.
ian
ian17mo ago
You can also break it up like: let query = db.query(…) If (condition) { query = query.filter(…) } return query.paginate(…) Let me know if it gives you more trouble
allen
allenOP17mo ago
@ian this was my first approach and I got an error around chaining
ian
ian17mo ago
Type error or runtime?
allen
allenOP17mo ago
runtime
ian
ian17mo ago
Odd. If you were doing (a||b).paginate you might need to .bind ? I can try to repro later
allen
allenOP17mo ago
the following code produces the attached error.
const query = db
.query('requests')
.withIndex('by_team', (q) => q.eq('teamId', team._id));

switch (args.type) {
case 'PENDING':
query.filter((q) => q.eq(q.field('isReleased'), false));
break;
case 'ACTIVE':
query.filter((q) =>
q.and(
q.eq(q.field('isReleased'), true),
q.eq(q.field('isExpired'), false),
),
);
break;

case 'CLOSED':
query.filter((q) => q.eq(q.field('isExpired'), true));
break;
}

return query.paginate(args.paginationOpts);
const query = db
.query('requests')
.withIndex('by_team', (q) => q.eq('teamId', team._id));

switch (args.type) {
case 'PENDING':
query.filter((q) => q.eq(q.field('isReleased'), false));
break;
case 'ACTIVE':
query.filter((q) =>
q.and(
q.eq(q.field('isReleased'), true),
q.eq(q.field('isExpired'), false),
),
);
break;

case 'CLOSED':
query.filter((q) => q.eq(q.field('isExpired'), true));
break;
}

return query.paginate(args.paginationOpts);
No description
ian
ian17mo ago
Ah you need to be calling query.paginate on the return from query.filter
allen
allenOP17mo ago
how is this different from your example above?
ian
ian17mo ago
query = query.filter
allen
allenOP17mo ago
i see
ian
ian17mo ago
We can work on that error message
allen
allenOP17mo ago
I suppose if db.query was a constructor this would work, but makes sense why it doesnt with my chaining approach. Just some patterns from working with MikroORM I need to shift on.
lee
lee11mo ago
for posterity, there's now an easier way to write completely arbitrary filters, and it works with pagination: https://stack.convex.dev/complex-filters-in-convex
Using TypeScript to Write Complex Query Filters
There’s a new Convex helper to perform generic TypeScript filters, with the same performance as built-in Convex filters, and unlimited potential.

Did you find this page helpful?