fix(plugin-import-export): csv export & preview showing full documents for hasMany monomorphic relationships instead of just ID (#13465)

### What?

Fixes an issue where CSV exports and the preview table displayed all
fields of documents in hasMany monomorphic relationships instead of only
their IDs.

### Why?

This caused cluttered output and inconsistent CSV formats, since only
IDs should be exported for hasMany monomorphic relationships.

### How?

Added explicit `toCSV` handling for all relationship types in
`getCustomFieldFunctions`, updated `flattenObject` to delegate to these
handlers, and adjusted `getFlattenedFieldKeys` to generate the correct
headers.
This commit is contained in:
Patrik
2025-08-13 16:54:32 -04:00
committed by GitHub
parent 0e8a6c0162
commit 3e65111bc1
7 changed files with 106 additions and 33 deletions

View File

@@ -221,6 +221,12 @@ export const Pages: CollectionConfig = {
relationTo: ['users', 'posts'],
hasMany: true,
},
{
name: 'hasManyMonomorphic',
type: 'relationship',
relationTo: 'posts',
hasMany: true,
},
{
type: 'collapsible',
label: 'Collapsible Field',

View File

@@ -598,6 +598,35 @@ describe('@payloadcms/plugin-import-export', () => {
expect(data[0].hasManyPolymorphic_1_relationTo).toBe('posts')
})
it('should export hasMany monomorphic relationship fields to CSV', async () => {
const doc = await payload.create({
collection: 'exports',
user,
data: {
collectionSlug: 'pages',
fields: ['id', 'hasManyMonomorphic'],
format: 'csv',
where: {
title: { contains: 'Monomorphic' },
},
},
})
const exportDoc = await payload.findByID({
collection: 'exports',
id: doc.id,
})
expect(exportDoc.filename).toBeDefined()
const expectedPath = path.join(dirname, './uploads', exportDoc.filename as string)
const data = await readCSV(expectedPath)
// hasManyMonomorphic
expect(data[0].hasManyMonomorphic_0_id).toBeDefined()
expect(data[0].hasManyMonomorphic_0_relationTo).toBeUndefined()
expect(data[0].hasManyMonomorphic_0_title).toBeUndefined()
})
// disabled so we don't always run a massive test
it.skip('should create a file from a large set of collection documents', async () => {
const allPromises = []

View File

@@ -242,6 +242,7 @@ export interface Page {
}
)[]
| null;
hasManyMonomorphic?: (string | Post)[] | null;
textFieldInCollapsible?: string | null;
updatedAt: string;
createdAt: string;
@@ -580,6 +581,7 @@ export interface PagesSelect<T extends boolean = true> {
excerpt?: T;
hasOnePolymorphic?: T;
hasManyPolymorphic?: T;
hasManyMonomorphic?: T;
textFieldInCollapsible?: T;
updatedAt?: T;
createdAt?: T;

View File

@@ -159,6 +159,16 @@ export const seed = async (payload: Payload): Promise<boolean> => {
})
}
for (let i = 0; i < 2; i++) {
await payload.create({
collection: 'pages',
data: {
title: `Monomorphic ${i}`,
hasManyMonomorphic: [posts[1]?.id ?? ''],
},
})
}
for (let i = 0; i < 5; i++) {
await payload.create({
collection: 'pages',