diff --git a/x-pack/plugins/lens/server/routes/existing_fields.test.ts b/x-pack/plugins/lens/server/routes/existing_fields.test.ts index 33541c7206c532..728b78c8e97bc4 100644 --- a/x-pack/plugins/lens/server/routes/existing_fields.test.ts +++ b/x-pack/plugins/lens/server/routes/existing_fields.test.ts @@ -172,4 +172,19 @@ describe('buildFieldList', () => { script: '2+2', }); }); + + it('handles missing mappings', () => { + const fields = buildFieldList(indexPattern, {}, fieldDescriptors); + expect(fields.every((f) => f.isAlias === false)).toEqual(true); + }); + + it('handles empty fieldDescriptors by skipping multi-mappings', () => { + const fields = buildFieldList(indexPattern, mappings, []); + expect(fields.find((f) => f.name === 'baz')).toMatchObject({ + isAlias: false, + isScript: false, + name: 'baz', + path: ['baz'], + }); + }); }); diff --git a/x-pack/plugins/lens/server/routes/existing_fields.ts b/x-pack/plugins/lens/server/routes/existing_fields.ts index 82185dd9ab4291..7ab3cdceb21457 100644 --- a/x-pack/plugins/lens/server/routes/existing_fields.ts +++ b/x-pack/plugins/lens/server/routes/existing_fields.ts @@ -41,8 +41,7 @@ export interface Field { script?: string; } -// TODO: Pull this from kibana advanced settings -const metaFields = ['_source', '_id', '_type', '_index', '_score']; +const metaFields = ['_source', '_type']; export async function existingFieldsRoute(setup: CoreSetup) { const router = setup.http.createRouter(); @@ -137,6 +136,18 @@ async function fetchIndexPatternDefinition(indexPatternId: string, context: Requ indexPatternId ); const indexPatternTitle = indexPattern.attributes.title; + + if (indexPatternTitle.includes(':')) { + // Cross cluster search patterns include a colon, and we aren't able to fetch + // mapping information. + return { + indexPattern, + indexPatternTitle, + mappings: {}, + fieldDescriptors: [], + }; + } + // TODO: maybe don't use IndexPatternsFetcher at all, since we're only using it // to look up field values in the resulting documents. We can accomplish the same // using the mappings which we're also fetching here. @@ -166,10 +177,10 @@ async function fetchIndexPatternDefinition(indexPatternId: string, context: Requ */ export function buildFieldList( indexPattern: SavedObject, - mappings: MappingResult, + mappings: MappingResult | {}, fieldDescriptors: FieldDescriptor[] ): Field[] { - const aliasMap = Object.entries(Object.values(mappings)[0].mappings.properties) + const aliasMap = Object.entries(Object.values(mappings)[0]?.mappings.properties ?? {}) .map(([name, v]) => ({ ...v, name })) .filter((f) => f.type === 'alias') .reduce((acc, f) => { @@ -242,6 +253,7 @@ async function fetchIndexPatternStats({ body: { size: SAMPLE_SIZE, query, + sort: timeFieldName && fromDate && toDate ? [{ [timeFieldName]: 'desc' }] : [], // _source is required because we are also providing script fields. _source: '*', script_fields: scriptedFields.reduce((acc, field) => {