One notification per like scales linearly with your viral posts — a post with 500 likes creates 500 bell pings, and the user stops opening the app. Grouping collapses that into 'Alex and 499 others liked your post,' which preserves the signal without the noise. Without batching, push-notification open rates crater, email digests become unreadable, and heavy users disable notifications platform-wide rather than per-type, which you cannot recover from.
Medium because ungrouped notifications actively drive users to disable the channel, which is hard to reverse.
On notification creation, upsert into an existing unread row keyed by (userId, type, targetId) — append the new actor to an actorIds array and increment similarCount instead of inserting a new row. Render the grouped form as 'FirstActor and N others your post.' See the notification creation path:
const existing = await db.notification.findFirst({ where: { type, targetId, userId, readAt: null } })
if (existing) return db.notification.update({ where: { id: existing.id }, data: { actorIds: [...new Set([...existing.actorIds, actorId])], similarCount: existing.similarCount + 1 } })
ID: community-social-engagement.notifications.batching-grouping
Severity: medium
What to look for: Enumerate all relevant files and Examine notification creation logic. Check whether multiple similar notifications are grouped together (e.g., "User A, User B, and 3 others liked your post" instead of 5 separate notifications). Look for aggregation queries or "latest actor" logic in the notification display component or database schema (e.g., a similar_count field).
Pass criteria: At least 1 conforming pattern must exist. Similar notifications are grouped. The UI shows aggregated notifications: "5 people liked your post" instead of 5 separate like notifications. Multiple notifications from the same type/action are consolidated.
Fail criteria: Each action creates a separate notification; users see 10 notifications if 10 people like a single post.
Skip (N/A) when: Notification grouping is not a concern or platform is very small-scale.
Detail on fail: "Each post like creates a separate notification — 100 likes = 100 notifications" or "No grouping logic in notification display component"
Remediation: Implement notification grouping:
// Notification model with grouping
model Notification {
id String @id
userId String
type String // 'likes', 'follows', 'comments'
targetId String // Post/User ID
actorIds String[] // Array of user IDs who triggered this notification
similarCount Int @default(0)
lastActorAt DateTime
readAt DateTime?
createdAt DateTime
}
// Group notifications on creation
async function createNotification(type: string, actorId: string, targetId: string, userId: string) {
const existing = await db.notification.findFirst({
where: { type, targetId, userId, readAt: null }
})
if (existing) {
// Update existing grouped notification
return db.notification.update({
where: { id: existing.id },
data: {
actorIds: [...new Set([...existing.actorIds, actorId])],
similarCount: existing.similarCount + 1,
lastActorAt: new Date()
}
})
} else {
// Create new notification
return db.notification.create({
data: { type, targetId, userId, actorIds: [actorId] }
})
}
}
// Display grouped notification
function NotificationItem({ notification }) {
if (notification.similarCount > 0) {
return (
<p>
{notification.actorIds[0]}, and {notification.similarCount} others {notification.type} your post
</p>
)
}
return <p>{notification.actorIds[0]} {notification.type}</p>
}