Reading Data
Objectives
By the end of this lesson, you should be able to:
- Use
findMany,findUnique, andfindFirstcorrectly - Filter results with
where, including multiple conditions - Choose the right find method for a given situation
💡 Why this matters: Every relationship from Module 5 was loaded with a read query. This lesson covers Prisma’s full reading API on its own, the direct replacement for the
SELECTstatements written by hand in Module 2.
⚠️ A note on verification: as throughout this module, the Prisma CLI can’t run inside this course’s own sandboxed tooling. The code below reflects Prisma Client’s stable, current, documented query API. Try it yourself, on your own machine, against a real database.
findMany
Returns every row matching the query, as an array:
const allStudents = await prisma.student.findMany();
console.log(allStudents);
[
{ id: 1, name: 'Erin', grade: 9 },
{ id: 2, name: 'Jordan', grade: 10 }
]
Filtering With where
const tenthGraders = await prisma.student.findMany({
where: { grade: 10 }
});
console.log(tenthGraders);
[ { id: 2, name: 'Jordan', grade: 10 } ]
This is the Prisma equivalent of SELECT * FROM students WHERE grade = $1, from Module 2, where is the direct replacement for WHERE.
Comparison Operators
Beyond exact matches, where accepts operators for ranges and comparisons:
const olderGrades = await prisma.student.findMany({
where: { grade: { gte: 10 } }
});
[ { id: 2, name: 'Jordan', grade: 10 } ]
gte (greater than or equal), alongside lt, lte, gt, and not, cover the same comparisons >, <, >=, <= do in raw SQL.
Multiple Conditions
const result = await prisma.student.findMany({
where: {
grade: { gte: 9 },
name: { contains: 'J' }
}
});
console.log(result);
[ { id: 2, name: 'Jordan', grade: 10 } ]
Multiple fields inside one where object are combined with AND by default. contains matches a substring, the equivalent of SQL’s LIKE '%J%'.
findUnique
Looks up exactly one row by a unique field (a primary key, or any field marked @unique), and returns null if nothing matches:
const student = await prisma.student.findUnique({
where: { id: 2 }
});
console.log(student);
{ id: 2, name: 'Jordan', grade: 10 }
findUnique only accepts fields that are actually unique, where: { grade: 10 } isn’t valid here, since more than one student could share a grade.
findFirst
Returns the first row matching any condition, unique or not, null if none match:
const first = await prisma.student.findFirst({
where: { grade: 10 }
});
console.log(first);
{ id: 2, name: 'Jordan', grade: 10 }
Use findUnique when looking up by something guaranteed unique (an ID, an email), and findFirst when the condition might match several rows but only one is needed.
Try It
- Fetch every student with
findMany(), and confirm the shape of the result (an array). - Filter with
where: { grade: { gte: 10 } }, and confirm only matching rows come back. - Look up one student by
idwithfindUnique, and confirm it returnsnullfor an ID that doesn’t exist. - Explain, in your own words, when
findUniqueshould be used instead offindFirst.
Recap
findManyreturns an array of matching rows,wherefilters them, directly replacing raw SQL’sWHERE.- Comparison operators (
gte,lt,contains, and more) cover the same ground as SQL’s>,<,LIKE. findUniquelooks up by a genuinely unique field and is the right tool for ID or email lookups,findFirstis for “the first match” on any condition.
Next lesson: writing data, create, update, and delete.