Reading Related Data
Prisma Fundamentals
Chapter 9 ยท Reading Related Data
Chapters 7 and 8 connected users, profiles, posts and tags. This chapter is about reading them back: loading a record together with its related records, choosing exactly which fields come back, filtering records by their relations, and avoiding the most common performance mistake in any ORM, the N+1 query problem.
include: Add Related Records
By default a query returns only the model's own fields. include adds relations on top:
Includes can be nested, to follow relations further:
Filtering, Sorting and Limiting Included Lists
include: { posts: true } is fine with ten posts and a problem with ten thousand: every one is loaded
into memory. For lists that can grow, add take, or load them separately with pagination
(Chapter 6).
select: Choose Exactly What Comes Back
select returns only the fields you list, including relations. It's the tool for keeping
responses small — and for keeping private fields private.
include | select | |
|---|---|---|
| Model's own fields | All of them | Only the ones you list |
| Relations | The ones you list, added on | The ones you list |
| Use for | "This record, plus its related data" | "Exactly these fields," such as for an API response |
include and select side by side at the same level of a query. You can mix
them at different levels, though: include: { author: { select: { name: true } } } returns all the
post's fields plus only the author's name.
include: { author: true } returns the whole user record. If your User model later gains a
passwordHash or other private field, every response built this way now contains it. For data sent to
browsers or other systems, select the fields you mean to share.
Filtering by Relations
You can also filter records by what their related records look like:
| Filter | For | Matches records where… |
|---|---|---|
some | Lists | At least one related record matches |
every | Lists | All related records match |
none | Lists | No related record matches |
is / isNot | Single relations | The related record matches / doesn't match |
every with some: {}.
The N+1 Query Problem
This code works, and it's a classic mistake:
One query for the list, then one more for every row: N+1 queries, 51 in this case. Each is quick, but they add up, especially when the database is on another machine and every query is a network round trip. The fix is to ask for the related data as part of the list query:
Prisma now loads the authors for all 50 posts together. By default it does this with one extra query for the
relation, however many posts there are, so the total stays fixed. On PostgreSQL, CockroachDB and MySQL, a
preview feature (relationJoins) can load everything in a single joined query instead.
Seeing the queries
Hands-On Exercises
Write a query for a blog's home page: the 10 newest published posts, each with its title, slug, publication date, author's name and tag names — and nothing else. Explain why you chose select or include.
Write queries for: (a) tags that aren't used on any post; (b) authors who have written at least one post tagged "prisma"; (c) users who have written posts and whose posts are all published.
๐ View solutionTurn on query logging, create at least 10 posts, and run this chapter's slow loop and fast version. Count the queries each makes, then explain how the counts would change with 1,000 posts.
๐ View solutionChapter 9 Quick Reference
includeadds relations to all of a model's fields; nest it to go deeper- Included lists accept
where,orderByandtake— bound lists that can grow selectreturns only the fields you list; prefer it for data you send elsewhere- Don't use
includeandselectat the same level; nesting them is fine - Relation filters:
some,every,nonefor lists;is,isNotfor single relations;everymatches empty lists - N+1: one query per row in a loop; fix it by loading the relation in the list query
log: ["query"]on the client shows every query Prisma runs