Build social features fast with mongoose-reactions — a tiny, production-ready Mongoose plugin for reactions

mongoose-reactions is a lightweight, TypeScript-first Mongoose plugin that adds Laravel-like polymorphic reactions (likes, loves, laughs, custom strings) to any model.

This post shows why you’ll want it in your stack, how it works, quickstart example…


This content originally appeared on DEV Community and was authored by Ali nazari

mongoose-reactions is a lightweight, TypeScript-first Mongoose plugin that adds Laravel-like polymorphic reactions (likes, loves, laughs, custom strings) to any model.

This post shows why you’ll want it in your stack, how it works, quickstart examples, scaling tips, and how you can help the project grow (⭐ GitHub!).

What this solves and why you should care

If you build social features (posts, comments, photos, products with likes), you need a fast, scalable, and developer-friendly way to attach reactions to any model.

mongoose-reactions:

  • Stores reactions in a single, indexed collection for efficient counts and queries.
  • Works polymorphically (one reactions collection — many models).
  • Is TypeScript-ready and tested for common concurrency edge cases.
  • Provides easy statics & instance helpers: react, unreact, toggleReaction, getReactionCounts, getUserReactions.
  • Plays nicely with transactions and bulk aggregation queries.

If you want to ship social features fast, avoid custom ad-hoc arrays in your documents, and keep your code clean and maintainable — this plugin is for you.

Why not just store reactions on the parent document?

Many early-stage apps put likes as an array on Post documents. That looks simple but quickly becomes painful:

  • Large arrays grow MongoDB documents to awkward sizes and harm performance.
  • Counting and listing across many posts (or across models) becomes expensive.
  • Deleting a user’s reactions (GDPR) requires scanning many documents.
  • Cross-model analytics (top-reacted posts vs comments) is hard.

By moving reactions into a small, indexed, dedicated collection you get:

  • O(1) writes (append-only docs), efficient aggregation for counts, and simpler migrations.
  • Single source of truth for reactions and easier features (undo, toggle, per-user lists).
  • Ability to add adapters later (Redis for counters, Prisma adapter, etc.).

Features at a glance

  • Polymorphic: store reactions for Post, Comment, Photo, etc., in one collection.
  • Configurable: single-reaction-per-user (default) or multi-reaction-per-user mode.
  • Validation: whitelist reaction types (e.g., ['like','love','haha']) with case-insensitive normalization.
  • Transaction-friendly: write operations can accept a session.
  • Bulk helpers: get counts for many reactables in one aggregation.
  • GDPR helpers: utilities to delete all reactions for a user or a reactable.
  • TypeScript types + Vitest testing scaffolding.

Quickstart — install & use

Install:

npm install mongoose mongoose-reactions
# or
pnpm add mongoose mongoose-reactions

Basic usage:

import mongoose from "mongoose";
import reactionsPlugin from "mongoose-reactions";

const PostSchema = new mongoose.Schema({ title: String });

PostSchema.plugin(reactionsPlugin, {
  reactionTypes: ['like','love','haha','angry'], // optional whitelist
  allowMultipleReactionsPerUser: false,          // default
});

const Post = mongoose.model('Post', PostSchema);

// react
await Post.react(postId, userId, 'like');               // static call
await postDoc.react(userId, 'love');                    // instance call

// counts (no need to pass model name; plugin infers it)
const counts = await Post.getReactionCounts(postId);    // -> { like: 12, love: 3 }

Express route sample:

import express from 'express';
const router = express.Router();

router.post('/posts/:id/reactions', async (req, res, next) => {
  try {
    const userId = req.user._id;            // assume auth middleware
    const postId = req.params.id;
    await Post.react(postId, userId, req.body.reaction);
    const counts = await Post.getReactionCounts(postId);
    res.json({ ok: true, counts });
  } catch (err) { next(err) }
});

API (developer-friendly)

Core methods exposed on any model you apply the plugin to:

  • Model.react(reactableId, userId, reaction, meta?, { session? }) - create/update reaction
  • Model.unreact(reactableId, userId, reaction?, { session? })- remove reaction(s)
  • Model.toggleReaction(reactableId, userId, reaction, meta?, { session? }) - toggle behavior
  • Model.getReactionCounts(reactableId)- { like: 10, love: 2 } (infers model)
  • Model.getUserReactions(reactableId, userId) - ReactionDoc[] (useful when multiple allowed)
  • Model.listReactors(reactableId , opts) - list users who reacted with optional reaction filter, paginated

Instance helpers map to the statics, so you can use postDoc.react(userId, 'like').

Polymorphism & model names — the small but crucial detail

The plugin stores a reactableModel (we recommend the Mongoose modelName like 'Post') alongside reactableId.

This avoids collisions when two models share the same id value and makes populate() and permissions checks straightforward.

We infer this.modelName inside statics — so you don’t need to pass the model name every time. Post.getReactionCounts(id) is enough.

If you like the plugin, please consider:

⭐ Star the GitHub repo — stars help the project show up in searches and attract contributors.


This content originally appeared on DEV Community and was authored by Ali nazari


Print Share Comment Cite Upload Translate Updates
APA

Ali nazari | Sciencx (2025-08-24T20:15:03+00:00) Build social features fast with mongoose-reactions — a tiny, production-ready Mongoose plugin for reactions. Retrieved from https://www.scien.cx/2025/08/24/build-social-features-fast-with-mongoose-reactions-a-tiny-production-ready-mongoose-plugin-for-reactions/

MLA
" » Build social features fast with mongoose-reactions — a tiny, production-ready Mongoose plugin for reactions." Ali nazari | Sciencx - Sunday August 24, 2025, https://www.scien.cx/2025/08/24/build-social-features-fast-with-mongoose-reactions-a-tiny-production-ready-mongoose-plugin-for-reactions/
HARVARD
Ali nazari | Sciencx Sunday August 24, 2025 » Build social features fast with mongoose-reactions — a tiny, production-ready Mongoose plugin for reactions., viewed ,<https://www.scien.cx/2025/08/24/build-social-features-fast-with-mongoose-reactions-a-tiny-production-ready-mongoose-plugin-for-reactions/>
VANCOUVER
Ali nazari | Sciencx - » Build social features fast with mongoose-reactions — a tiny, production-ready Mongoose plugin for reactions. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/08/24/build-social-features-fast-with-mongoose-reactions-a-tiny-production-ready-mongoose-plugin-for-reactions/
CHICAGO
" » Build social features fast with mongoose-reactions — a tiny, production-ready Mongoose plugin for reactions." Ali nazari | Sciencx - Accessed . https://www.scien.cx/2025/08/24/build-social-features-fast-with-mongoose-reactions-a-tiny-production-ready-mongoose-plugin-for-reactions/
IEEE
" » Build social features fast with mongoose-reactions — a tiny, production-ready Mongoose plugin for reactions." Ali nazari | Sciencx [Online]. Available: https://www.scien.cx/2025/08/24/build-social-features-fast-with-mongoose-reactions-a-tiny-production-ready-mongoose-plugin-for-reactions/. [Accessed: ]
rf:citation
» Build social features fast with mongoose-reactions — a tiny, production-ready Mongoose plugin for reactions | Ali nazari | Sciencx | https://www.scien.cx/2025/08/24/build-social-features-fast-with-mongoose-reactions-a-tiny-production-ready-mongoose-plugin-for-reactions/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.