如何在Prisma中按类型统计各帖子的Reaction数量?
解决方案:用Prisma或原生SQL实现帖子反应统计
你既可以用Prisma实现需求,也可以直接使用原生PostgreSQL SQL,两种方式都能高效完成统计,无需拉取大量Reaction记录。
方式一:用Prisma ORM实现
如果你的反应类型是固定的(比如只有like、thumbsup),可以利用Prisma的关联查询和聚合计数功能,直接在findMany中定义各类型的统计字段,类型安全且代码简洁。
Prisma Schema 示例
首先确保你的schema定义了正确的关联关系:
model Post { id Int @id @default(autoincrement()) title String reactions Reaction[] } model Reaction { id Int @id @default(autoincrement()) userId Int postId Int reactionType ReactionType post Post @relation(fields: [postId], references: [id]) @@unique([userId, postId, reactionType]) // 避免同一用户对同一帖子重复添加同类型反应 } enum ReactionType { like thumbsup // 可添加其他反应类型 }
查询代码
const postsWithStats = await prisma.post.findMany({ select: { id: true, title: true, // 统计like类型的数量 likeCount: { _count: { where: { reactionType: 'like' } } }, // 统计thumbsup类型的数量 thumbsupCount: { _count: { where: { reactionType: 'thumbsup' } } }, // 其他反应类型的统计同理添加 }, });
查询结果中,没有对应反应的帖子会返回0作为计数。
方式二:用原生PostgreSQL SQL实现
如果你的反应类型是动态的(后续可能新增类型),或者需要更灵活的统计格式,直接用原生SQL会更高效。你可以通过CASE语句拆分各类型计数,或者用JSON函数将统计结果打包成对象。
固定类型统计SQL
SELECT p.id, p.title, COALESCE(SUM(CASE WHEN r.reactionType = 'like' THEN 1 ELSE 0 END), 0) AS like_count, COALESCE(SUM(CASE WHEN r.reactionType = 'thumbsup' THEN 1 ELSE 0 END), 0) AS thumbsup_count FROM "Post" p LEFT JOIN "Reaction" r ON p.id = r."postId" GROUP BY p.id, p.title;
动态类型统计(返回JSON)
如果要自动适配所有存在的反应类型,用json_object_agg将统计结果转为JSON对象:
SELECT p.id, p.title, COALESCE( json_object_agg(r.reactionType, COUNT(r.id)), '{}'::json ) AS reaction_counts FROM "Post" p LEFT JOIN "Reaction" r ON p.id = r."postId" GROUP BY p.id, p.title;
这个查询会返回一个reaction_counts字段,格式类似{"like":3,"thumbsup":1},无反应的帖子返回空对象{}。
在Prisma中执行原生SQL
你可以通过Prisma的$queryRaw方法直接执行上述SQL:
const postsWithStats = await prisma.$queryRaw` SELECT p.id, p.title, COALESCE(json_object_agg(r.reactionType, COUNT(r.id)), '{}'::json) AS reaction_counts FROM "Post" p LEFT JOIN "Reaction" r ON p.id = r."postId" GROUP BY p.id, p.title; `;
总结
- 若反应类型固定,优先用Prisma的关联聚合查询,类型安全且符合ORM开发习惯;
- 若反应类型动态或需要灵活格式,用原生SQL(可通过Prisma执行)更合适,性能也更优。
内容的提问来源于stack exchange,提问作者Talin
相关产品推荐
相关产品推荐

