Skip to content

Commit 488e12f

Browse files
author
Wylie Conlon
authored
[Lens] Fix existence for dotted paths in _source (elastic#63752) (elastic#63893)
1 parent c5fc56c commit 488e12f

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

x-pack/plugins/lens/server/routes/existing_fields.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,24 @@ describe('existingFields', () => {
5757
expect(result).toEqual(['geo.coordinates']);
5858
});
5959

60+
it('should handle objects with dotted fields', () => {
61+
const result = existingFields(
62+
[indexPattern({ 'geo.country_name': 'US' })],
63+
[field('geo.country_name')]
64+
);
65+
66+
expect(result).toEqual(['geo.country_name']);
67+
});
68+
69+
it('should handle arrays with dotted fields on both sides', () => {
70+
const result = existingFields(
71+
[indexPattern({ 'process.cpu': [{ 'user.pct': 50 }] })],
72+
[field('process.cpu.user.pct')]
73+
);
74+
75+
expect(result).toEqual(['process.cpu.user.pct']);
76+
});
77+
6078
it('should be false if it hits a positive leaf before the end of the path', () => {
6179
const result = existingFields(
6280
[indexPattern({ geo: { coordinates: 32 } })],

x-pack/plugins/lens/server/routes/existing_fields.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ async function fetchIndexPatternStats({
258258
return result.hits.hits;
259259
}
260260

261+
// Recursive function to determine if the _source of a document
262+
// contains a known path.
261263
function exists(obj: unknown, path: string[], i = 0): boolean {
262264
if (obj == null) {
263265
return false;
@@ -272,6 +274,22 @@ function exists(obj: unknown, path: string[], i = 0): boolean {
272274
}
273275

274276
if (typeof obj === 'object') {
277+
// Because Elasticsearch flattens paths, dots in the field name are allowed
278+
// as JSON keys. For example, { 'a.b': 10 }
279+
const partialKeyMatches = Object.getOwnPropertyNames(obj)
280+
.map(key => key.split('.'))
281+
.filter(keyPaths => keyPaths.every((key, keyIndex) => key === path[keyIndex + i]));
282+
283+
if (partialKeyMatches.length) {
284+
return partialKeyMatches.every(keyPaths => {
285+
return exists(
286+
(obj as Record<string, unknown>)[keyPaths.join('.')],
287+
path,
288+
i + keyPaths.length
289+
);
290+
});
291+
}
292+
275293
return exists((obj as Record<string, unknown>)[path[i]], path, i + 1);
276294
}
277295

0 commit comments

Comments
 (0)