diff --git a/.changeset/cold-coats-show.md b/.changeset/cold-coats-show.md new file mode 100644 index 0000000000..a048ec308c --- /dev/null +++ b/.changeset/cold-coats-show.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Fix for duplicate search results in entity-facets API call diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts index 0b8dec71bb..e9d00f3451 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts @@ -2359,6 +2359,52 @@ describe('DefaultEntitiesCatalog', () => { }); }, ); + + it.each(databases.eachSupportedId())( + 'works when the entity is duplicated in search results, %p', + async databaseId => { + await createDatabase(databaseId); + + await addEntityToSearch({ + apiVersion: 'a', + kind: 'k', + metadata: { + name: 'one', + uid: 'uid-a', + }, + spec: {}, + }); + + // Manually insert a duplicate search entry, this shouldn't happen but does in reality + await knex('search').insert([ + { + entity_id: 'uid-a', + key: 'metadata.name', + value: 'one', + original_value: 'one', + }, + ]); + + const catalog = new DefaultEntitiesCatalog({ + database: knex, + logger: mockServices.logger.mock(), + stitcher, + }); + + await expect( + catalog.facets({ + facets: ['metadata.name'], + credentials: mockCredentials.none(), + }), + ).resolves.toEqual({ + facets: { + 'metadata.name': expect.arrayContaining([ + { value: 'one', count: 1 }, + ]), + }, + }); + }, + ); }); }); diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts index 33847ea87b..92c0bb0ecf 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts @@ -683,7 +683,7 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { .select({ facet: 'search.key', value: 'search.original_value', - count: this.database.raw('count(*)'), + count: this.database.raw('count(DISTINCT search.entity_id)'), }) .groupBy(['search.key', 'search.original_value']);