Filtering, Sorting & Pagination
Prisma Fundamentals
Chapter 6 ยท Filtering, Sorting & Pagination
Chapter 5's queries used simple conditions such as { published: false }. Real applications need
more: posts with "prisma" in the title, published this month, newest first, twenty to a page. This chapter
covers the filtering, sorting and paging options, and one trap — case sensitivity — that behaves
differently on every database.
Filter Operators
Writing { published: true } is shorthand for { published: { equals: true } }. Instead of a
plain value, a field can take an object of operators:
| Operator | Example | Matches |
|---|---|---|
equals, not | { title: { not: "Draft" } } | Equal / not equal |
in, notIn | { id: { in: [1, 2, 3] } } | Any value in the list / none of them |
lt, lte, gt, gte | { viewCount: { gte: 100 } } | Less than, less or equal, greater than, greater or equal |
contains | { title: { contains: "prisma" } } | Text containing the value |
startsWith, endsWith | { slug: { startsWith: "how-to" } } | Text beginning / ending with the value |
Several conditions at the top level of where are combined with AND: a post must match all of them.
Matching NULL
null and undefined are very different in a where. { content: null }
finds rows where content is empty; { content: undefined } is ignored completely. So if a search
function builds where: { title: searchTerm } and searchTerm is undefined, the filter
vanishes and you get every post. Check inputs before using them.
Combining Conditions: AND, OR and NOT
OR takes a list, and a row matches if any item matches. AND takes a list too, and
is useful when you need the same field twice. NOT excludes rows that match. They can be nested as
deeply as you need.
Case Sensitivity: Different on Every Database
Does contains: "prisma" match a title containing "Prisma"? It depends on the database.
| Database | Default text matching | Case-insensitive option |
|---|---|---|
| PostgreSQL | Case-sensitive | Add mode: "insensitive" |
| MongoDB | Case-sensitive | Add mode: "insensitive" |
| MySQL | Usually case-insensitive (depends on the column's collation) | Already insensitive by default |
| SQL Server | Usually case-insensitive | Already insensitive by default |
| SQLite | Not case-insensitive for columns Prisma creates | Edit the migration to add COLLATE NOCASE to the column |
Sorting
orderBy, the database may return rows in any order it likes, and that order can change
between queries. Paging without a fixed sort can show the same post twice or skip one entirely.
Pagination
Offset pagination: take and skip
Simple, and it lets users jump to any page number. But the database still has to count past every skipped row, so very deep pages get slower, and if posts are added while someone is paging, items shift between pages.
Cursor pagination
Offset (skip/take) | Cursor | |
|---|---|---|
| Jump to page 7 | Yes | No — only next/previous |
| Speed on deep pages | Gets slower | Stays fast |
| New rows while paging | Items can shift or repeat | Stable |
| Good for | Admin tables, numbered pages | Infinite scroll, feeds, large tables |
Removing Duplicates: distinct
Hands-On Exercises
Write a query for published posts that either have at least 50 views or were published in the last 7 days, excluding any whose slug starts with draft-, sorted by views (most first) then title.
Write a searchPosts(term?: string, page = 1) function that returns 10 published posts per page, newest first, filtered by title if a term is given, along with the total number of pages. Make sure a missing term can't accidentally return drafts.
On your SQLite project, create posts titled "Prisma Tips" and "prisma tricks", then search with contains: "prisma". Explain the result, and what you'd change to make the search case-insensitive on SQLite and on PostgreSQL.
Chapter 6 Quick Reference
- Operators:
equals,not,in,notIn,lt/lte/gt/gte,contains,startsWith,endsWith - Top-level conditions are ANDed; combine with
AND,OR(lists) andNOT nullmatches empty values;undefinedremoves the condition entirely- Case sensitivity varies:
mode: "insensitive"on PostgreSQL and MongoDB; MySQL and SQL Server are usually insensitive; SQLite needsCOLLATE NOCASE orderBytakes one object or a list;{ sort, nulls: "first" | "last" }controls empty values- Offset paging:
skip+take(pluscountfor totals); cursor paging:cursor,skip: 1,take - Always
orderBywhen paging;distinctremoves duplicate rows