prisma: `take` key doesn't work correctly for nested query that returns one item with its nested children

Bug description

If we have a nested query, and we have take key present in the query. It doesn’t generate the correct raw query. The limit key isn’t there when the query is converted into the raw query by prisma. This results in huge latencies for querying data.

How to reproduce

sync db with the given schema and run the given query.

We will have two tables created. one for Person and another for Cars. a Person can have many Cars by definition. When the given query ( to get a person and include the cars ) , prisma generates the following queries :

q1 )SELECT "public"."Person"."id", "public"."Person"."name" FROM "public"."Person" WHERE "public"."Person"."id" = $1 LIMIT $2 OFFSET $3 [1,1,0]

q2) SELECT "public"."Cars"."id", "public"."Cars"."ownerId" FROM "public"."Cars" WHERE "public"."Cars"."ownerId" IN ($1) ORDER BY "public"."Cars"."id" ASC OFFSET $2 [1,0]

If we look at the second query we can see the limit keyword is not applied over here. Whereas this is specified in the prima query written in the code. Whats happening is that prisma is fetching all the cars for this person and handling the limit in the code . This creates huge latencies if we want to fetch only one car ( by specifying limit as 1 ) and the person has lots of cars, as prisma will fetch all the cars from the DB and return us one car for the person.

Expected behavior

Ideally, prisma should add the limit key to the query such that we retrieve only the desired results.

Prisma information


model Person {
  id              Int                 @id @default(autoincrement())
  name          String
  Cars Cars[]
}

model Cars {
  id      Int             @id @default(autoincrement())
  owner     Person @relation(references: [id], fields: [ownerId], onDelete: Cascade)
  ownerId   Int

}

await this.prisma.person.findFirst({
                where:{
                    id:1
                },
                include:{
                    Cars:{
                        take:1
                    }
                }
            })

Environment & setup

  • OS: Macos
  • Database: Postgres
  • Node.js version: 14.18.0

Prisma Version

3.12 and 4.4

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 6
  • Comments: 18 (6 by maintainers)

Most upvoted comments

@janpio Sorry we can’t be of much help here, we actually moved this specific query to a different api which uses sqlalchemy and had no issues there. Unfortunate that prisma couldn’t handle this use case right now but didn’t end up being a major blocker for us.

If we didn’t have the option we would have either gone with the same approach @livthomas mentioned or just had done it raw.

Sounds good to me, but I’ll avoid any use of nested take until both are fixed.

Thanks!

@janpio This issue is about nested queries with take: 1 where LIMIT is not being added to the actual SQL query.

An example of one of our queries affected by this bug:

    await prisma.zone.findMany({
      select: {
        syncs: {
          select: {
            id: true,
          },
          orderBy: {id: 'desc'},
          take: 1,
          where: {
            status: SyncStatus.FINISHED,
          },
        },
      }
    });

We used nested selects with take: 1 also in other methods (findUnique, findFirst, or groupBy) but I’m not sure if all of them cause this issue. We decided to rewrite all the queries immediately when we discovered this bug.