diff --git a/src/utils/schema/resolvers/Query/all.ts b/src/utils/schema/resolvers/Query/all.ts index 99acf524f..13070491d 100644 --- a/src/utils/schema/resolvers/Query/all.ts +++ b/src/utils/schema/resolvers/Query/all.ts @@ -81,6 +81,10 @@ export const buildProjectAggregation = ( if (queryFields && Array.isArray(queryFields)) { queryFields.forEach((field) => { data[field.name] = 1; + // Also project resource fields at root level since they're populated there + if (field.fields && field.fields.length > 0) { + staticProject[field.name] = 1; + } }); staticProject.data = data; } @@ -88,7 +92,12 @@ export const buildProjectAggregation = ( staticProject.data[field.name] = 1; }); sort.forEach((item: any) => { - staticProject.data[item.name] = 1; + // For nested fields we need to project the parent field at root level + const fieldName = item.field + ? item.field.split('.')[0] + : item.name?.split('.')[0] || item.name; + staticProject.data[fieldName] = 1; + staticProject[fieldName] = 1; }); return [{ $project: staticProject }]; }; diff --git a/src/utils/schema/resolvers/Query/getSortAggregation.ts b/src/utils/schema/resolvers/Query/getSortAggregation.ts index 6e84999f2..8078af3f5 100644 --- a/src/utils/schema/resolvers/Query/getSortAggregation.ts +++ b/src/utils/schema/resolvers/Query/getSortAggregation.ts @@ -24,11 +24,51 @@ const getSortAggregation = async ( sortFields = [{ field: 'createdAt', order: 'asc' }]; } await sortFields.forEach(async (item: { field: string; order: string }) => { - const field: any = fields.find((x) => x && x.name === item.field); - const parentField: any = - item.field && item.field.includes('.') - ? fields.find((x) => x && x.name === item.field.split('.')[0]) - : ''; + // Check if this is a nested field + const isNestedField = item.field && item.field.includes('.'); + const fieldName = isNestedField ? item.field.split('.')[0] : item.field; + + const field: any = fields.find((x) => x && x.name === fieldName); + const parentField: any = isNestedField + ? fields.find((x) => x && x.name === fieldName) + : ''; + // For nested fields, use the full path as-is since the aggregation pipeline + // in all.ts already flattens resource fields properly + if (isNestedField) { + aggregationSort = { + ...aggregationSort, + [item.field]: getSortOrder(item.order), + }; + return; + } + // Handle resource fields - after projection they're at top level with nested structure + if (field && (field.type === 'resource' || field.type === 'resources')) { + // Resource fields are projected at top level after aggregation + // Sort by the display field if available, otherwise fallback to 'name' + const sortPath = field.displayField + ? `${item.field}.${field.displayField}` + : `${item.field}.name`; + + aggregationSort = { + ...aggregationSort, + [sortPath]: getSortOrder(item.order), + }; + return; + } + // Handle reference data fields - these are also projected at top level + if (field && field.referenceData?.id) { + // Reference data fields are projected at top level + // Sort by the display field if available + const sortPath = field.referenceData.displayField + ? `${item.field}.${field.referenceData.displayField}` + : `${item.field}`; + + aggregationSort = { + ...aggregationSort, + [sortPath]: getSortOrder(item.order), + }; + return; + } // If we need to populate choices to sort on the text value if (field && (field.choices || field.choicesByUrl)) { const choices = await getFullChoices(field, context);