MongoDB $mergeObjects Accumulator

Beginner
5 min read
Updated: Oct 2026
3 examples
Live preview

What Is $mergeObjects?

$mergeObjects combines documents into one document. As a $group accumulator, each grouped document contributes one object; the result is a single merged object per group.

Remember
$mergeObjects = fold documents into one object

accumulator → { $mergeObjects: "$field" }   // one expr
expression  → { $mergeObjects: [ a, b, c ] } // fixed list

same field twice? → last value wins
null operand?     → ignored (all null → { })
UsePrefer
Combine nested maps per group$mergeObjects
Collect values into an array$push
Unique array elements$setUnion

How to Use $mergeObjects in MongoDB

As an accumulator, pass one document expression.

  1. Put $mergeObjects inside $group on an output field.
  2. Pass a field path that resolves to a document (e.g. "$quantity").
  3. Choose _id for the group key (item, user, year, …).
  4. Remember: when field names collide, the last document wins.
FormSyntaxRole
Accumulator{ $mergeObjects: "$doc" }One object per grouped document
Expression{ $mergeObjects: [ a, b ] }Merge a fixed list of documents
Stages$group, $bucket, $bucketAutoAlso usable in $replaceRoot as expression

Pseudocode

Pseudocode
for each group:
    result = {}
    for each document in group:
        obj = evaluate(expression)   // must be a document
        if obj is not null:
            for each key in obj:
                result[key] = obj[key]   // overwrite if exists
    emit { _id: groupKey, field: result }

Cheat Sheet

Keep these facts handy while merging objects.

TopicDetail
Accumulator syntax{ $mergeObjects: "$field" } (single operand)
Expression syntax{ $mergeObjects: [ doc1, doc2 ] }
Colliding fieldsLast document’s value wins
nullIgnored; all null → { }
Operand typeMust resolve to a document (not an array of docs)
Sample checkitem A quarters from 2016 + 2017 → one map

Live Preview

Watch profile fields merge per user. Sample: Sam (city + role), Sam (role + team), Mia (city), Mia (team + city).

Simulates last-wins merge of the data object for each user.

Result
sam: {} + {city, role} → {city: "New York", role: "dev"}
sam: + {role, team} → {city: "New York", role: "lead", team: "platform"}
mia: {} + {city} → {city: "Chicago"}
mia: + {team, city} → {city: "Austin", team: "design"}

[
  { _id: "mia", profile: { city: "Austin", team: "design" } },
  { _id: "sam", profile: { city: "New York", role: "lead", team: "platform" } }
]

Worked Walkthrough — Merge Profiles

Four profile patches, two users. Watch Sam’s role update from dev to lead, and Mia’s city from Chicago to Austin.

Calculation
Documents:
  { user: "sam", data: { city: "New York", role: "dev" } }
  { user: "sam", data: { role: "lead", team: "platform" } }
  { user: "mia", data: { city: "Chicago" } }
  { user: "mia", data: { team: "design", city: "Austin" } }

user "sam":
  {} + { city, role: "dev" }
    → { city: "New York", role: "dev" }
  + { role: "lead", team }
    → { city: "New York", role: "lead", team: "platform" }

user "mia":
  {} + { city: "Chicago" } → { city: "Chicago" }
  + { team, city: "Austin" } → { city: "Austin", team: "design" }

MongoDB Examples

First we merge user profile patches. Then we merge quarterly sales maps by item (the classic MongoDB docs pattern). Run these in mongosh after inserting each sample once.

Example 1 — Profile Sample Data

Imagine profile updates arriving as separate documents. Each has a user and a data object with some fields.

mongosh
db.profiles.insertMany([
  { user: "sam", data: { city: "New York", role: "dev" } },
  { user: "sam", data: { role: "lead", team: "platform" } },
  { user: "mia", data: { city: "Chicago" } },
  { user: "mia", data: { team: "design", city: "Austin" } }
]);

How the Data Is Stored in MongoDB

After the insert, MongoDB keeps 4 documents in profiles. Run find() to see them:

mongosh
db.profiles.find()

Read each document like this:

Field in MongoDBMeaningExample
userWhose profile patch this is"sam"
dataObject fields to merge{ role: "lead" }
Picture
Sam patches:
  1) { city: "New York", role: "dev" }
  2) { role: "lead", team: "platform" }

$mergeObjects combines them (later keys win on conflict).

How It Works

  1. Insert once. The sample command adds 4 documents to profiles.
  2. MongoDB stores fields as written. Each document keeps the same field names and values you inserted.
  3. find() shows the same shape. What you inserted is what you get back—ready for $mergeObjects in the next examples.

Example 2 — Merge Profiles per User

Goal: one combined profile object per user. Fields present in later documents overwrite earlier ones.

mongosh
db.profiles.aggregate([
  {
    $group: {
      _id: "$user",
      // single document expression — accumulator form
      profile: { $mergeObjects: "$data" }
    }
  },
  { $sort: { _id: 1 } }
]);

How It Works

  1. Split by user. _id: "$user" makes groups for Sam and Mia.
  2. Merge each data object. Accumulator form takes one expression: "$data".
  3. Last wins on collisions. Sam’s role becomes "lead"; Mia’s city becomes "Austin".
  4. New fields are added. team appears when a later document introduces it.
  5. Need an array of patches instead? Use $push.

Example 3 — Merge Quarterly Sales Maps

Goal: one quantity map per item across years. Each document holds a nested quantity object with quarter keys.

mongosh
db.sales.insertMany([
  { year: 2017, item: "A", quantity: { "2017Q1": 500, "2017Q2": 500 } },
  { year: 2016, item: "A", quantity: { "2016Q1": 400, "2016Q2": 300, "2016Q3": 0, "2016Q4": 0 } },
  { year: 2017, item: "B", quantity: { "2017Q1": 300 } },
  { year: 2016, item: "B", quantity: { "2016Q3": 100, "2016Q4": 250 } }
]);

db.sales.aggregate([
  {
    $group: {
      _id: "$item",
      mergedSales: { $mergeObjects: "$quantity" }
    }
  },
  { $sort: { _id: 1 } }
]);

How It Works

  1. Group by item. Item A and item B each get one output document.
  2. Merge quarter maps. Every quantity object contributes its keys.
  3. No colliding keys here. Each quarter key appears once, so nothing is overwritten.
  4. One flat map. Years stay as separate field names inside a single object—handy for reports.
  5. Expression form elsewhere. In $replaceRoot you often use the array form: { $mergeObjects: [ a, b ] }.

Edge Cases & Pitfalls

Check these before shipping a merge report.

overwrite

Last document wins

Colliding field names keep the value from the last document processed. Sort first if you need a specific winner.

null

Null operands are ignored

A null data field is skipped. If every value is null, the result is { }.

syntax

Accumulator takes one expression

Do not pass an array of documents to the accumulator form. Use "$field", not [ "$a", "$b" ], inside $group.

nested

Shallow merge only

Nested objects under the same key are replaced entirely, not deep-merged field by field.

Performance Notes

ApproachCostBest for
$mergeObjectsOne growing object per groupCombining sparse maps / patches
$pushArray grows with every docKeeping every version separately

Prefer $mergeObjects when you want one flat map. Huge objects with many colliding keys still scan every document once—filter early with $match when you can.

Key Takeaways

  • Role: fold document fields into one object per group.
  • Rule: last value wins when field names collide.
  • Syntax: accumulator = one expression; expression form = array of docs.
  • Null: ignored; all null returns { }.

One line: $mergeObjects builds one document from many—perfect for sparse maps and patch-style fields.

Frequently Asked Questions

$mergeObjects combines multiple documents into one. As a $group accumulator it merges one object from each document in the group into a single embedded document per group.
Inside $group (also $bucket / $bucketAuto): { merged: { $mergeObjects: "$profile" } }. The operand must be a single expression that resolves to a document—not an array of documents.
As an accumulator: { $mergeObjects: <one document expression> }. As a general expression: { $mergeObjects: [ doc1, doc2, ... ] }. The array form merges a fixed list; the accumulator merges one object per grouped document.
Later values overwrite earlier ones. If three documents in a group all have a status field, the merged object keeps the value from the last document processed for that field.
Null operands are ignored. If every document in a group resolves to null, $mergeObjects returns an empty object { }.
$mergeObjects merges object fields into one document. $setUnion works on arrays and returns unique elements. Use $mergeObjects for nested maps; use $setUnion for tag lists.

Next: $min

Return the smallest value in each group.

$min tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

9 people found this page helpful