CodingNic

CRUD and Querying with Prisma

Reading Data

CRUD and Querying with Prisma 15 min read

Reading Data

Objectives

By the end of this lesson, you should be able to:

  • Use findMany, findUnique, and findFirst correctly
  • 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 SELECT statements 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:

javascript
const allStudents = await prisma.student.findMany();
console.log(allStudents);
text
[
  { id: 1, name: 'Erin', grade: 9 },
  { id: 2, name: 'Jordan', grade: 10 }
]

Filtering With where

javascript
const tenthGraders = await prisma.student.findMany({
  where: { grade: 10 }
});
console.log(tenthGraders);
text
[ { 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:

javascript
const olderGrades = await prisma.student.findMany({
  where: { grade: { gte: 10 } }
});
text
[ { 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

javascript
const result = await prisma.student.findMany({
  where: {
    grade: { gte: 9 },
    name: { contains: 'J' }
  }
});
console.log(result);
text
[ { 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:

javascript
const student = await prisma.student.findUnique({
  where: { id: 2 }
});
console.log(student);
text
{ 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:

javascript
const first = await prisma.student.findFirst({
  where: { grade: 10 }
});
console.log(first);
text
{ 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

  1. Fetch every student with findMany(), and confirm the shape of the result (an array).
  2. Filter with where: { grade: { gte: 10 } }, and confirm only matching rows come back.
  3. Look up one student by id with findUnique, and confirm it returns null for an ID that doesn’t exist.
  4. Explain, in your own words, when findUnique should be used instead of findFirst.

Recap

  • findMany returns an array of matching rows, where filters them, directly replacing raw SQL’s WHERE.
  • Comparison operators (gte, lt, contains, and more) cover the same ground as SQL’s >, <, LIKE.
  • findUnique looks up by a genuinely unique field and is the right tool for ID or email lookups, findFirst is for “the first match” on any condition.

Next lesson: writing data, create, update, and delete.