From 0cbb48dd0baba3b57116226ca363ded2791d2eb9 Mon Sep 17 00:00:00 2001 From: lcnogueira Date: Wed, 15 Apr 2026 23:12:12 -0300 Subject: [PATCH 1/5] fix(db-postgres): handle ['null'] array form when filtering hasMany relationship by None --- packages/drizzle/src/queries/sanitizeQueryValue.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/drizzle/src/queries/sanitizeQueryValue.ts b/packages/drizzle/src/queries/sanitizeQueryValue.ts index 5959a02722c..fc8d2abc7bc 100644 --- a/packages/drizzle/src/queries/sanitizeQueryValue.ts +++ b/packages/drizzle/src/queries/sanitizeQueryValue.ts @@ -141,7 +141,7 @@ export const sanitizeQueryValue = ({ } if (field.type === 'relationship' || field.type === 'upload') { - if (val === 'null') { + if (val === 'null' || (Array.isArray(val) && val.length === 1 && val[0] === 'null')) { formattedValue = null } else if (!(formattedValue === null || typeof formattedValue === 'boolean')) { // convert the value to the idType of the relationship From 2af1354ff26ba69663bed0bd82df6968668fa591 Mon Sep 17 00:00:00 2001 From: lcnogueira Date: Wed, 15 Apr 2026 23:26:46 -0300 Subject: [PATCH 2/5] test(db-postgres): add test for equals null on hasMany relationship field --- test/relationships/int.spec.ts | 49 ++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/relationships/int.spec.ts b/test/relationships/int.spec.ts index 930f5456cb8..9f94e711c4f 100644 --- a/test/relationships/int.spec.ts +++ b/test/relationships/int.spec.ts @@ -704,6 +704,55 @@ describe('Relationships', () => { expect(query.docs[0].text).toEqual('Tree 3') expect(query.docs[1].text).toEqual('Tree 4') }) + + it('should query using "equals: null" on a hasMany relationship field', async () => { + const movie = await payload.create({ + collection: 'movies', + data: { name: 'Some Movie' }, + }) + + const directorWithMovies = await payload.create({ + collection: 'directors', + data: { + name: 'Director With Movies', + movies: [movie.id], + }, + }) + + const directorWithoutMovies = await payload.create({ + collection: 'directors', + data: { + name: 'Director Without Movies', + }, + }) + + // Test programmatic API with null + const programmaticResult = await payload.find({ + collection: 'directors', + depth: 0, + where: { + movies: { equals: null }, + }, + }) + + expect(programmaticResult.totalDocs).toBe(1) + expect(programmaticResult.docs[0]?.id).toBe(directorWithoutMovies.id) + + // Test REST API with ['null'] — the form the admin UI sends for "None" + const restResult = await restClient + .GET(`/directors`, { + query: { + where: { + movies: { equals: ['null'] }, + }, + depth: 0, + }, + }) + .then((res) => res.json()) + + expect(restResult.totalDocs).toBe(1) + expect(restResult.docs[0]?.id).toBe(directorWithoutMovies.id) + }) }) describe('sorting by relationships', () => { From 080e1a6772ef8ed3593bc21e7895fecb3a1c9180 Mon Sep 17 00:00:00 2001 From: lcnogueira Date: Wed, 15 Apr 2026 23:27:13 -0300 Subject: [PATCH 3/5] test(db-postgres): fix type cast and unused variable in hasMany null filter test --- test/relationships/int.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/relationships/int.spec.ts b/test/relationships/int.spec.ts index 9f94e711c4f..74ce1f4567b 100644 --- a/test/relationships/int.spec.ts +++ b/test/relationships/int.spec.ts @@ -711,7 +711,7 @@ describe('Relationships', () => { data: { name: 'Some Movie' }, }) - const directorWithMovies = await payload.create({ + await payload.create({ collection: 'directors', data: { name: 'Director With Movies', @@ -748,7 +748,7 @@ describe('Relationships', () => { depth: 0, }, }) - .then((res) => res.json()) + .then((res) => res.json() as Promise<{ docs: Director[]; totalDocs: number }>) expect(restResult.totalDocs).toBe(1) expect(restResult.docs[0]?.id).toBe(directorWithoutMovies.id) From ff31bb3f72b9d02c5ae00aed133c44a429e7219f Mon Sep 17 00:00:00 2001 From: lcnogueira Date: Thu, 16 Apr 2026 07:50:01 -0300 Subject: [PATCH 4/5] test(db-postgres): clean up directors and movies before hasMany null filter test --- test/relationships/int.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/relationships/int.spec.ts b/test/relationships/int.spec.ts index 74ce1f4567b..ff184d29376 100644 --- a/test/relationships/int.spec.ts +++ b/test/relationships/int.spec.ts @@ -706,6 +706,9 @@ describe('Relationships', () => { }) it('should query using "equals: null" on a hasMany relationship field', async () => { + await payload.delete({ collection: 'directors', where: {} }) + await payload.delete({ collection: 'movies', where: {} }) + const movie = await payload.create({ collection: 'movies', data: { name: 'Some Movie' }, From 203cd3bc20c324356ad0a7e3dd8647f2477bd040 Mon Sep 17 00:00:00 2001 From: lcnogueira Date: Thu, 16 Apr 2026 08:16:51 -0300 Subject: [PATCH 5/5] fix(db-mongodb): handle ['null'] array form when filtering hasMany relationship by None --- packages/db-mongodb/src/queries/sanitizeQueryValue.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/db-mongodb/src/queries/sanitizeQueryValue.ts b/packages/db-mongodb/src/queries/sanitizeQueryValue.ts index ca9bb27e7b6..79fa5ebc3f0 100644 --- a/packages/db-mongodb/src/queries/sanitizeQueryValue.ts +++ b/packages/db-mongodb/src/queries/sanitizeQueryValue.ts @@ -210,7 +210,7 @@ export const sanitizeQueryValue = ({ } if (['relationship', 'upload'].includes(field.type)) { - if (val === 'null') { + if (val === 'null' || (Array.isArray(val) && val.length === 1 && val[0] === 'null')) { formattedValue = null }