diff --git a/src/topics/tags.js b/src/topics/tags.js index 7f60096cd1..48bbb44e15 100644 --- a/src/topics/tags.js +++ b/src/topics/tags.js @@ -256,14 +256,21 @@ module.exports = function (Topics) { }; async function removeTagsFromTopics(tags) { - await async.eachLimit(tags, 50, async (tag) => { - const tids = await db.getSortedSetRange(`tag:${tag}:topics`, 0, -1); - if (!tids.length) { - return; - } + const uniqTids = new Set(); + const tagsToRemove = new Set(tags); + + await batch.processArray(tags, async (tags) => { + await Promise.all(tags.map(async (tag) => { + await batch.processSortedSet(`tag:${tag}:topics`, async (tids) => { + tids.forEach(tid => uniqTids.add(tid)); + }, { batch: 500 }); + })); + }, { batch: 50 }); + + await batch.processArray(Array.from(uniqTids), async (tids) => { let topicsTags = await Topics.getTopicsTags(tids); topicsTags = topicsTags.map( - topicTags => topicTags.filter(topicTag => topicTag && topicTag !== tag) + topicTags => topicTags.filter(tag => tag && !tagsToRemove.has(tag)) ); await db.setObjectBulk( @@ -271,7 +278,7 @@ module.exports = function (Topics) { `topic:${tid}`, { tags: topicsTags[index].join(',') }, ])) ); - }); + }, { batch: 500 }); } async function removeTagsFromUsers(tags) { diff --git a/test/topics.js b/test/topics.js index 21ecffd245..f70bd301fb 100644 --- a/test/topics.js +++ b/test/topics.js @@ -1632,15 +1632,18 @@ describe('Topic\'s', () => { assert.deepStrictEqual(tags, ['deleteme1', 'deleteme3']); }); - it('should delete tag', (done) => { - topics.deleteTag('javascript', (err) => { - assert.ifError(err); - db.getObject('tag:javascript', (err, data) => { - assert.ifError(err); - assert(!data); - done(); - }); - }); + it('should delete tag', async () => { + await topics.deleteTag('javascript'); + const data = await db.getObject('tag:javascript'); + assert(!data); + }); + + it('should properly remove tags from topic hash when removing all tags of a topic', async () => { + const result1 = await topics.post({ uid: adminUid, tags: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5'], title: 'many tags much wow', content: 'topic 1 content', cid: topic.categoryId }); + await topics.deleteTags(['tag1', 'tag2', 'tag3', 'tag4', 'tag5']); + const topicData = await topics.getTopicData(result1.topicData.tid); + const tags = topicData.tags.map(t => t.value); + assert.deepStrictEqual(tags, []); }); it('should delete category tag as well', async () => {