elastic/kibana
View on GitHub[Saved Objects] KQL Filter should support matching root and type fields
Open
#239704 opened on Oct 20, 2025
Team:Corebuggood first issue
Description
Saved Objects find method allows specifying a KQL filter like foo.updated_at targeting the root field updated_at or foo.attributes.name targeting the name field defined on the saved object type foo.
However, if there's a type field that matches a root field like foo.attributes.update_at then it's no longer possible to filter on the root field.
The diff below is an example of the kind of test we would want to pass after adding the updated_at type field to the mockMappings (just for illustration, when implementing we might decide to edit existing tests or write a slightly different test)
diff --git a/src/core/packages/saved-objects/api-server-internal/src/lib/search/utils/filter_utils.test.ts b/src/core/packages/saved-objects/api-server-internal/src/lib/search/utils/filter_utils.test.ts
index 333c0c1b3afb..ac567d97014c 100644
--- a/src/core/packages/saved-objects/api-server-internal/src/lib/search/utils/filter_utils.test.ts
+++ b/src/core/packages/saved-objects/api-server-internal/src/lib/search/utils/filter_utils.test.ts
@@ -33,6 +33,9 @@ const mockMappings = {
bytes: {
type: 'integer',
},
+ updated_at: {
+ type: 'date',
+ },
},
},
bar: {
@@ -279,6 +282,26 @@ describe('Filter Utils', () => {
validateConvertFilterToKueryNode([], 'hiddentype.title: "title"', mockMappings);
}).toThrowErrorMatchingInlineSnapshot(`"This type hiddentype is not allowed: Bad Request"`);
});
+
+ test('Verify that foo.updated_at targets root field and foo.attributes.updated_at targets type field', () => {
+ // Test foo.updated_at (should target root updated_at field)
+ const rootFieldResult = validateConvertFilterToKueryNode(
+ ['foo'],
+ 'foo.updated_at: 5678654567',
+ mockMappings
+ );
+ expect(rootFieldResult).toEqual(
+ esKuery.fromKueryExpression('(type: foo and updated_at: 5678654567)')
+ );
+
+ // Test foo.attributes.updated_at (should target type-specific updated_at field)
+ const typeFieldResult = validateConvertFilterToKueryNode(
+ ['foo'],
+ 'foo.attributes.updated_at: 5678654567',
+ mockMappings
+ );
+ expect(typeFieldResult).toEqual(esKuery.fromKueryExpression('foo.updated_at: 5678654567'));
+ });
});
describe('#validateFilterKueryNode', () => {