From 3c48081be9c068c2ba61cf7cf4f1a71db780c245 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 18 Mar 2021 17:35:47 +0900 Subject: [PATCH] perf: reduce query --- src/services/note/reaction/create.ts | 51 ++++++++++++++++------------ 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/src/services/note/reaction/create.ts b/src/services/note/reaction/create.ts index adc96ddc1..8de9f53a1 100644 --- a/src/services/note/reaction/create.ts +++ b/src/services/note/reaction/create.ts @@ -11,33 +11,40 @@ import { perUserReactionsChart } from '../../chart'; import { genId } from '../../../misc/gen-id'; import { createNotification } from '../../create-notification'; import deleteReaction from './delete'; +import { isDuplicateKeyValueError } from '../../../misc/is-duplicate-key-value-error'; export default async (user: User, note: Note, reaction?: string) => { reaction = await toDbReaction(reaction, user.host); - const exist = await NoteReactions.findOne({ - noteId: note.id, - userId: user.id, - }); - - if (exist) { - if (exist.reaction !== reaction) { - // 別のリアクションがすでにされていたら置き換える - await deleteReaction(user, note); - } else { - // 同じリアクションがすでにされていたら何もしない - return; - } - } + let record; // Create reaction - const inserted = await NoteReactions.save({ - id: genId(), - createdAt: new Date(), - noteId: note.id, - userId: user.id, - reaction - }); + try { + record = await NoteReactions.save({ + id: genId(), + createdAt: new Date(), + noteId: note.id, + userId: user.id, + reaction + }); + } catch (e) { + if (isDuplicateKeyValueError(e)) { + record = await NoteReactions.findOneOrFail({ + noteId: note.id, + userId: user.id, + }); + + if (record.reaction !== reaction) { + // 別のリアクションがすでにされていたら置き換える + await deleteReaction(user, note); + } else { + // 同じリアクションがすでにされていたら何もしない + return; + } + } else { + throw e; + } + } // Increment reactions count const sql = `jsonb_set("reactions", '{${reaction}}', (COALESCE("reactions"->>'${reaction}', '0')::int + 1)::text::jsonb)`; @@ -101,7 +108,7 @@ export default async (user: User, note: Note, reaction?: string) => { //#region 配信 if (Users.isLocalUser(user) && !note.localOnly) { - const content = renderActivity(await renderLike(inserted, note)); + const content = renderActivity(await renderLike(record, note)); const dm = new DeliverManager(user, content); if (note.userHost !== null) { const reactee = await Users.findOne(note.userId);