fix(CQ-API-7): Fix N+1 query in knowledge tag lookup
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Replace Promise.all of individual findUnique queries per tag with a single findMany batch query. Only missing tags are created individually. Tag associations now use createMany instead of individual creates. Also deduplicates tags by slug via Map, preventing duplicate entries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -821,45 +821,48 @@ export class KnowledgeService {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get or create tags
|
||||
const tags = await Promise.all(
|
||||
tagNames.map(async (name) => {
|
||||
const tagSlug = this.generateSlug(name);
|
||||
// Build slug map: slug -> original tag name
|
||||
const slugToName = new Map<string, string>();
|
||||
for (const name of tagNames) {
|
||||
slugToName.set(this.generateSlug(name), name);
|
||||
}
|
||||
const tagSlugs = [...slugToName.keys()];
|
||||
|
||||
// Try to find existing tag
|
||||
let tag = await tx.knowledgeTag.findUnique({
|
||||
where: {
|
||||
workspaceId_slug: {
|
||||
workspaceId,
|
||||
slug: tagSlug,
|
||||
},
|
||||
},
|
||||
});
|
||||
// Batch fetch all existing tags in a single query (fixes N+1)
|
||||
const existingTags = await tx.knowledgeTag.findMany({
|
||||
where: {
|
||||
workspaceId,
|
||||
slug: { in: tagSlugs },
|
||||
},
|
||||
});
|
||||
|
||||
// Create if doesn't exist
|
||||
tag ??= await tx.knowledgeTag.create({
|
||||
// Determine which tags need to be created
|
||||
const existingSlugs = new Set(existingTags.map((t) => t.slug));
|
||||
const missingSlugs = tagSlugs.filter((s) => !existingSlugs.has(s));
|
||||
|
||||
// Create missing tags
|
||||
const newTags = await Promise.all(
|
||||
missingSlugs.map((slug) => {
|
||||
const name = slugToName.get(slug) ?? slug;
|
||||
return tx.knowledgeTag.create({
|
||||
data: {
|
||||
workspaceId,
|
||||
name,
|
||||
slug: tagSlug,
|
||||
slug,
|
||||
},
|
||||
});
|
||||
|
||||
return tag;
|
||||
})
|
||||
);
|
||||
|
||||
// Create tag associations
|
||||
await Promise.all(
|
||||
tags.map((tag) =>
|
||||
tx.knowledgeEntryTag.create({
|
||||
data: {
|
||||
entryId,
|
||||
tagId: tag.id,
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
const allTags = [...existingTags, ...newTags];
|
||||
|
||||
// Create tag associations in a single batch
|
||||
await tx.knowledgeEntryTag.createMany({
|
||||
data: allTags.map((tag) => ({
|
||||
entryId,
|
||||
tagId: tag.id,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user