fix(db-postgres): incorrect pagination results when querying hasMany relationships multiple times (#11096)

Fixes https://github.com/payloadcms/payload/issues/10810

This was caused by using `COUNT(*)` aggregation instead of
`COUNT(DISTINCT table.id)`. However, we want to use `COUNT(*)` because
`COUNT(DISTINCT table.id)` is slow on large tables. Now we fallback to
`COUNT(DISTINCT table.id)` only when `COUNT(*)` cannot work properly.

Example of a query that leads to incorrect `totalDocs`:
```ts
const res = await payload.find({
  collection: 'directors',
  limit: 10,
  where: {
    or: [
      {
        movies: {
          equals: movie2.id,
        },
      },
      {
        movies: {
          equals: movie1.id,
        },
      },
      {
        movies: {
          equals: movie1.id,
        },
      },
    ],
  },
})
```
This commit is contained in:
Sasha
2025-02-11 01:16:18 +02:00
committed by GitHub
parent fde526e07f
commit 98fec35368
6 changed files with 89 additions and 13 deletions

View File

@@ -412,6 +412,51 @@ describe('Relationships', () => {
expect(customIdNumberRelation).toMatchObject({ id: generatedCustomIdNumber })
})
it('should retrieve totalDocs correctly with hasMany,', async () => {
const movie1 = await payload.create({
collection: 'movies',
data: {},
})
const movie2 = await payload.create({
collection: 'movies',
data: {},
})
await payload.create({
collection: 'directors',
data: {
name: 'Quentin Tarantino',
movies: [movie2.id, movie1.id],
},
})
const res = await payload.find({
collection: 'directors',
limit: 10,
where: {
or: [
{
movies: {
equals: movie2.id,
},
},
{
movies: {
equals: movie1.id,
},
},
{
movies: {
equals: movie1.id,
},
},
],
},
})
expect(res.totalDocs).toBe(1)
})
it('should query using "contains" by hasMany relationship field', async () => {
const movie1 = await payload.create({
collection: 'movies',
@@ -498,6 +543,7 @@ describe('Relationships', () => {
},
})
// eslint-disable-next-line jest/no-standalone-expect
expect(query1.totalDocs).toStrictEqual(1)
})
@@ -1424,6 +1470,7 @@ describe('Relationships', () => {
})
.then((res) => res.json())
// eslint-disable-next-line jest/no-standalone-expect
expect(queryOne.docs).toHaveLength(1)
})