DocsHub
Back-EndSchemas

Social Media Schema

Complete MongoDB schemas for a social media app — Post, Like, Comment, Follow, and Notification.

Social Media Schema

Schemas for a social platform — posts with embedded likes for fast access, a separate Follow model for the social graph, and notifications.


Post Schema

// src/models/post.model.js
import mongoose from "mongoose";

const postSchema = new mongoose.Schema(
  {
    author: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
    content: {
      type: String,
      maxlength: 500,
    },
    images: [{ type: String }],
    // likes stored as an array of user ids — fast for small-medium scale
    likes: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
    commentsCount: {
      type: Number,
      default: 0,
    },
    sharesCount: {
      type: Number,
      default: 0,
    },
  },
  { timestamps: true }
);

const Post = mongoose.model("Post", postSchema);

export default Post;

Comment Schema

// src/models/comment.model.js
import mongoose from "mongoose";

const commentSchema = new mongoose.Schema(
  {
    post: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Post",
      required: true,
    },
    author: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
    content: {
      type: String,
      required: true,
      maxlength: 300,
    },
    likes: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
  },
  { timestamps: true }
);

const Comment = mongoose.model("Comment", commentSchema);

export default Comment;

Follow Schema

// src/models/follow.model.js
import mongoose from "mongoose";

const followSchema = new mongoose.Schema(
  {
    follower: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
    following: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
  },
  { timestamps: true }
);

// prevent following the same person twice
followSchema.index({ follower: 1, following: 1 }, { unique: true });

const Follow = mongoose.model("Follow", followSchema);

export default Follow;

Notification Schema

// src/models/notification.model.js
import mongoose from "mongoose";

const notificationSchema = new mongoose.Schema(
  {
    recipient: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
    sender: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
    type: {
      type: String,
      enum: ["like", "comment", "follow", "mention"],
      required: true,
    },
    post: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Post",
    },
    isRead: {
      type: Boolean,
      default: false,
    },
  },
  { timestamps: true }
);

const Notification = mongoose.model("Notification", notificationSchema);

export default Notification;

Common Usage Patterns

// toggle a like on a post
const post = await Post.findById(postId);
const alreadyLiked = post.likes.includes(userId);

if (alreadyLiked) {
  post.likes.pull(userId);
} else {
  post.likes.push(userId);

  // create a notification for the post author
  await Notification.create({
    recipient: post.author,
    sender: userId,
    type: "like",
    post: post._id,
  });
}

await post.save();
// follow a user
await Follow.create({ follower: currentUserId, following: targetUserId });

await Notification.create({
  recipient: targetUserId,
  sender: currentUserId,
  type: "follow",
});
// get a user's follower count and following count
const followerCount = await Follow.countDocuments({ following: userId });
const followingCount = await Follow.countDocuments({ follower: userId });

Storing likes as an embedded array on Post works well at small to medium scale. For apps with millions of likes per post, switch to a separate Like collection with post and user fields, similar to the Follow model — embedded arrays become slow to update at very large sizes.


Summary

  • Post.likes is an embedded array of user ids — simple and fast for typical app sizes
  • Follow is a separate collection with a compound unique index on follower + following — this is the standard pattern for social graphs, not an embedded array on User
  • Notification tracks type with an enum so the frontend can render different notification messages and icons
  • Use .pull() and .push() on Mongoose arrays to toggle likes without re-fetching the whole array manually
  • At very large scale, move likes from an embedded array to its own collection like Follow

On this page