Skip to content

Commit 2b1b6ee

Browse files
authored
fix: findDistinct by explicit ID paths in relationships and virtual fields (#14215)
Fixes `findDistinct` operation when the `field` argument is: * an eplicit ID path inside a relationship like: ```ts const distinct = await payload.findDistinct({ collection: 'posts', field: 'category.id' }) ``` * A virtual field linked to a relationship ID field ```ts [ { type: 'relationship', relationTo: 'categories', name: 'category', }, { type: 'number', name: 'categoryID', virtual: 'category.id', }, ] const distinct = await payload.findDistinct({ collection: 'posts', field: 'categoryID' }) ```
1 parent a3b3865 commit 2b1b6ee

File tree

5 files changed

+51
-1
lines changed

5 files changed

+51
-1
lines changed

packages/db-mongodb/src/findDistinct.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ export const findDistinct: FindDistinct = async function (this: MongooseAdapter,
6767
let tempPath = ''
6868
let insideRelation = false
6969

70-
for (const segment of args.field.split('.')) {
70+
const segments = args.field.split('.')
71+
72+
for (let i = 0; i < segments.length; i++) {
73+
const segment = segments[i]
7174
const field = currentFields.find((e) => e.name === segment)
7275
if (rels.length) {
7376
insideRelation = true
@@ -92,6 +95,11 @@ export const findDistinct: FindDistinct = async function (this: MongooseAdapter,
9295
(field.type === 'relationship' || field.type === 'upload') &&
9396
typeof field.relationTo === 'string'
9497
) {
98+
if (i === segments.length - 2 && segments[i + 1] === 'id') {
99+
foundField = field
100+
fieldPath = tempPath
101+
break
102+
}
95103
rels.push({ fieldPath: tempPath, relationTo: field.relationTo })
96104
currentFields = this.payload.collections[field.relationTo]?.config
97105
.flattenedFields as FlattenedField[]

packages/payload/src/utilities/getFieldByPath.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ export const getFieldByPath = ({
6262
if (flattenedFields) {
6363
currentFields = flattenedFields
6464
}
65+
66+
if (segments.length === 1 && segments[0] === 'id') {
67+
return { field, localizedPath, pathHasLocalized }
68+
}
6569
}
6670

6771
if ('blocks' in field) {

test/database/getConfig.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ export const getConfig: () => Partial<Config> = () => ({
131131
relationTo: 'categories',
132132
name: 'category',
133133
},
134+
{
135+
type: 'json',
136+
name: 'categoryID',
137+
virtual: 'category.id',
138+
},
134139
{
135140
type: 'text',
136141
name: 'categoryTitle',

test/database/int.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,29 @@ describe('database', () => {
13101310
])
13111311
})
13121312

1313+
it('should find distinct values when the virtual field is linked to ID', async () => {
1314+
await payload.delete({ collection: 'posts', where: {} })
1315+
await payload.delete({ collection: 'categories', where: {} })
1316+
const category = await payload.create({
1317+
collection: 'categories',
1318+
data: { title: 'category' },
1319+
})
1320+
await payload.create({ collection: 'posts', data: { title: 'post', category } })
1321+
const distinct = await payload.findDistinct({ collection: 'posts', field: 'categoryID' })
1322+
expect(distinct.values).toStrictEqual([{ categoryID: category.id }])
1323+
})
1324+
1325+
it('should find distinct values by the explicit ID field path', async () => {
1326+
await payload.delete({ collection: 'posts', where: {} })
1327+
await payload.delete({ collection: 'categories', where: {} })
1328+
const category = await payload.create({
1329+
collection: 'categories',
1330+
data: { title: 'category' },
1331+
})
1332+
await payload.create({ collection: 'posts', data: { title: 'post', category } })
1333+
const distinct = await payload.findDistinct({ collection: 'posts', field: 'category.id' })
1334+
expect(distinct.values).toStrictEqual([{ 'category.id': category.id }])
1335+
})
13131336
describe('Compound Indexes', () => {
13141337
beforeEach(async () => {
13151338
await payload.delete({ collection: 'compound-indexes', where: {} })

test/database/payload-types.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,15 @@ export interface Post {
209209
id: string;
210210
title: string;
211211
category?: (string | null) | Category;
212+
categoryID?:
213+
| {
214+
[k: string]: unknown;
215+
}
216+
| unknown[]
217+
| string
218+
| number
219+
| boolean
220+
| null;
212221
categoryTitle?: string | null;
213222
categorySimpleText?: string | null;
214223
categories?: (string | Category)[] | null;
@@ -882,6 +891,7 @@ export interface CategoriesCustomIdSelect<T extends boolean = true> {
882891
export interface PostsSelect<T extends boolean = true> {
883892
title?: T;
884893
category?: T;
894+
categoryID?: T;
885895
categoryTitle?: T;
886896
categorySimpleText?: T;
887897
categories?: T;

0 commit comments

Comments
 (0)