mongoui

Solution

Find and remove duplicate documents in MongoDB, safely

Finding duplicates in MongoDB is an aggregation. Removing them is a decision you make carefully. The whole problem is choosing the key that defines what counts as the same document, then keeping one per group.

Last reviewed July 4, 2026

Finding duplicate documents in MongoDB is an aggregation. Removing them is a decision, and it is yours to make, because only you know your data. The whole task comes down to one choice: the key that defines what counts as the same document. Get that right and the cleanup is short and safe. Get it wrong and you delete rows that were never duplicates.

Find the duplicates first

Group the collection on the identity field, keep the _id values, and count each group:

db.users.aggregate([
  { $group: {
      _id: "$email",
      ids: { $push: "$_id" },
      count: { $sum: 1 }
  } },
  { $match: { count: { $gt: 1 } } }
])

Every group that comes back has more than one document sharing that email, and the ids array holds their _id values. That is your list of duplicate clusters. Nothing has been deleted; you have only looked. The $group reference covers the operators if you want to group on more than one field.

The dedup key is the whole problem

Before you delete anything, question the key. A collection can look like it has ten thousand duplicate users when you group on email alone. Group on the key that actually defines identity here, email plus tenantId, and it is two hundred, most of them legitimate accounts in different tenants.

{ $group: {
    _id: { email: "$email", tenantId: "$tenantId" },
    ids: { $push: "$_id" },
    count: { $sum: 1 }
} }

A good dedup key is often a composite, and sometimes there is not one. If two documents share an email but differ in every field that matters, they are not duplicates, they are two records. The honest answer is occasionally "leave them." A tool that decides "the same" for you is deciding what to delete for you, and that is not its decision to make.

Remove them, carefully

This is the part where the jokes stop. You are about to write to a production collection, so move slowly.

Decide which document in each cluster you keep (usually the oldest, or the one with the most complete data), and collect every other _id into a list to remove. Then, before deleting, count exactly what the delete will match:

// Preview: how many documents will this remove?
db.users.countDocuments({ _id: { $in: idsToRemove } })

Read that number and make sure it matches what you expect. A delete filter written quickly can match far more than you intended. Only when the count is right do you run the delete:

db.users.deleteMany({ _id: { $in: idsToRemove } })

Keep a backup or a snapshot before the delete, so an undo is possible if the key was wrong after all.

Prevent the next batch

Once the collection is clean, stop the problem at the source with a unique index on the identity key:

db.users.createIndex({ email: 1, tenantId: 1 }, { unique: true })

New inserts that would create a duplicate are rejected at write time. Build it after the cleanup, not before, or the index build fails on the existing conflicts. See MongoDB index optimization for keeping that index lean.

Or resolve them behind a dry run

mongoui's duplicate finder groups documents on the fields you pick, shows you the clusters, and lets you resolve them, never a blind delete. Every removal is a dry run first: the exact before and after counts, on a sample or the full collection, before a single write. Applied changes keep a snapshot, so undo is one click.

The engine runs on your machine, so the documents you are grouping and comparing never leave your network. Choose the key, review the clusters, apply behind the gate. Your duplicates stop multiplying, and nothing legitimate gets caught in the sweep.

Frequently asked questions

How do I find duplicate documents in MongoDB?

Group on the field that defines identity and count the groups: db.users.aggregate([{ $group: { _id: "$email", ids: { $push: "$_id" }, count: { $sum: 1 } } }, { $match: { count: { $gt: 1 } } }]). Every group with a count above one is a duplicate cluster.

How do I remove duplicates in MongoDB with an aggregation?

The aggregation finds duplicates; it does not delete them. Collect the _id values you want to remove (every id in a cluster except the one you keep), review the list, then delete with deleteMany. On a production collection, preview the exact count before you run the delete.

How do I choose the right dedup key?

Pick the fields that actually define identity for your data. Grouping users on email alone may flag ten thousand duplicates; grouping on email plus tenantId may leave two hundred, most of them legitimate. A good key is often a composite, and sometimes the honest answer is that these are not duplicates.

How do I prevent duplicate documents in MongoDB?

Add a unique index on the identity key: db.users.createIndex({ email: 1, tenantId: 1 }, { unique: true }). New inserts that violate it are rejected. Create it after the existing duplicates are resolved, or the index build fails on the conflicts.