Definition
Note
This page describes the $merge stage, which outputs the aggregation pipeline results to a collection. For the $mergeObjects operator, which merges documents into a single document, see $mergeObjects.
$mergeWrites the results of the aggregation pipeline to a specified collection. The
$mergeoperator must be the last stage in the pipeline.The
$mergestage:Can output to a collection in the same or different database.
Can output to the same collection that is being aggregated. For more information, see Output to the Same Collection that is Being Aggregated.
Consider the following points when using
$mergeor$outstages in an aggregation pipeline:Starting in MongoDB 5.0, pipelines with a
$mergestage can run on replica set secondary nodes if all the nodes in the cluster have the featureCompatibilityVersion set to5.0or higher and the read preference allows secondary reads.In earlier MongoDB versions, pipelines with
$outor$mergestages always run on the primary node and read preference isn't considered.
Creates a new collection if the output collection does not already exist.
Can incorporate results (insert new documents, merge documents, replace documents, keep existing documents, fail the operation, process documents with a custom update pipeline) into an existing collection.
Can output to a sharded collection. Input collection can also be sharded.
For a comparison with the
$outstage which also outputs the aggregation results to a collection, see$mergeand$outComparison.
Note
On-Demand Materialized Views
$merge can incorporate the pipeline results into an existing output collection rather than perform a full replacement of the collection. This functionality allows users to create on-demand materialized views, where the content of the output collection is incrementally updated when the pipeline is run.
For more information on this use case, see On-Demand Materialized Views as well as the examples on this page.
Materialized views are separate from read-only views. For information on creating read-only views, see read-only views.
Compatibility
You can use $merge for deployments hosted in the following environments:
- MongoDB Atlas: The fully managed service for MongoDB deployments in the cloud
MongoDB Enterprise: The subscription-based, self-managed version of MongoDB
MongoDB Community: The source-available, free-to-use, and self-managed version of MongoDB
Syntax
$merge has the following syntax:
{ $merge: { into: <collection> -or- { db: <db>, coll: <collection> }, on: <identifier field> -or- [ <identifier field1>, ...], // Optional let: <variables>, // Optional whenMatched: <replace|keepExisting|merge|fail|pipeline>, // Optional whenNotMatched: <insert|discard|fail> // Optional } }
For example:
{ $merge: { into: "myOutput", on: "_id", whenMatched: "replace", whenNotMatched: "insert" } }
If using all default options for $merge, including writing to a collection in the same database, you can use the simplified form:
{ $merge: <collection> } // Output collection is in the same database
The $merge stage takes a document with the following fields:
Field | Description | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
The output collection. Specify either:
If the output collection does not exist,
The output collection can be a sharded collection. | |||||||||||
Optional. Field or fields that act as a unique identifier for a document. The identifier determines if a results document matches an existing document in the output collection. Specify either:
For the specified field or fields:
The default value for on depends on the output collection:
| |||||||||||
Optional. The behavior of You can specify either:
| |||||||||||
Optional. Specifies variables for use in the whenMatched pipeline. Specify a document with the variable names and value expressions: If unspecified, defaults to To access the variables in the whenMatched pipeline: Specify the double dollar sign ($$) prefix together with the variable name in the form For examples, see Use Variables to Customize the Merge. | |||||||||||
Optional. The behavior of You can specify one of the pre-defined action strings:
|
Considerations
_id Field Generation
If the _id field is not present in a document from the aggregation pipeline results, the $merge stage generates it automatically.
For example, in the following aggregation pipeline, $project excludes the _id field from the documents passed into $merge. When $merge writes these documents to the "newCollection", $merge generates a new _id field and value.
db.movies.aggregate( [ { $project: { _id: 0 } }, { $merge : { into : "newCollection" } } ] )
Create a New Collection if Output Collection is Non-Existent
The $merge operation creates a new collection if the specified output collection does not exist.
The output collection is created when
$mergewrites the first document into the collection and is immediately visible.If the aggregation fails, any writes completed by the
$mergebefore the error will not be rolled back.
Note
For a replica set or a standalone, if the output database does not exist, $merge also creates the database.
For a sharded cluster, the specified output database must already exist.
If the output collection does not exist, $merge requires the on identifier to be the _id field. To use a different on field value for a collection that does not exist, you can create the collection first by creating a unique index on the desired field(s) first. For example, if the output collection newDailyCommentCount does not exist and you want to specify the commentDate field as the on identifier:
db.newDailyCommentCount.createIndex( { commentDate: 1 }, { unique: true } ) db.comments.aggregate( [ { $match: { date: { $gte: new Date("2002-01-01"), $lt: new Date("2002-02-01") } } }, { $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: "$date" } }, count: { $sum: 1 } } }, { $project: { _id: 0, commentDate: { $toDate: "$_id" }, count: 1 } }, { $merge : { into : "newDailyCommentCount", on: "commentDate" } } ] )
Output to a Sharded Collection
The $merge stage can output to a sharded collection. When the output collection is sharded, $merge uses the _id field and all the shard key fields as the default on identifier. If you override the default, the on identifier must include all the shard key fields:
{ $merge: { into: "<shardedColl>" or { db:"<sharding enabled db>", coll: "<shardedColl>" }, on: [ "<shardkeyfield1>", "<shardkeyfield2>",... ], // Shard key fields and any additional fields let: <variables>, // Optional whenMatched: <replace|keepExisting|merge|fail|pipeline>, // Optional whenNotMatched: <insert|discard|fail> // Optional } }
For example, use the sh.shardCollection() method to create a new sharded collection moviesByYearAndRating with the rated field as the shard key.
sh.shardCollection( "sample_mflix.moviesByYearAndRating", // Namespace of the collection to shard { rated: 1 }, // Shard key );
The moviesByYearAndRating collection will contain documents with movie statistics by year (year field) and content rating (shard key); specifically, the on identifier is ["year", "rated"] (the ordering of the fields does not matter). Because $merge requires a unique index with keys that correspond to the on identifier fields, create the unique index (the ordering of the fields do not matter): [1]
db.moviesByYearAndRating.createIndex( { rated: 1, year: 1 }, { unique: true } )
With the sharded collection moviesByYearAndRating and the unique index created, you can use $merge to output the aggregation results to this collection, matching on [ "year", "rated" ] as in this example:
db.movies.aggregate( [ { $match: { rated: { $ne: null }, year: { $ne: null } } }, { $group: { _id: { year: "$year", rated: "$rated" }, movieCount: { $sum: 1 } } }, { $project: { _id: 0, year: "$_id.year", rated: "$_id.rated", movieCount: 1 } }, { $merge: { into: "moviesByYearAndRating", "on": [ "year", "rated" ], whenMatched: "replace", whenNotMatched: "insert" } } ] )
| [1] | The In the previous example, because the |
Replace Documents ($merge) vs Replace Collection ($out)
$merge can replace an existing document in the output collection if the aggregation results contain a document or documents that match based on the on specification. As such, $merge can replace all documents in the existing collection if the aggregation results include matching documents for all existing documents in the collection and you specify "replace" for whenMatched.
However, to replace an existing collection regardless of the aggregation results, use $out instead.
Existing Documents and _id and Shard Key Values
The $merge errors if the $merge results in a change to an existing document's _id value.
Tip
To avoid this error, if the on field does not include the _id field, remove the _id field in the aggregation results to avoid the error, such as with a preceding $unset stage, and so on.
Additionally, for a sharded collection, $merge also generates an error if it results in a change to the shard key value of an existing document.
Any writes completed by the $merge before the error will not be rolled back.
Unique Index Constraints
If the unique index used by $merge for on field(s) is dropped mid-aggregation, there is no guarantee that the aggregation will be killed. If the aggregation continues, there is no guarantee that documents do not have duplicate on field values.
If the $merge attempts to write a document that violates any unique index on the output collection, the operation generates an error. For example:
Insert a non-matching document that violates a unique index other than the index on the on field(s).
Replace an existing document with a new document that violates a unique index other than the index on the on field(s).
Merge the matching documents that results in a document that violates a unique index other than the index on the on field(s).
Schema Validation
If your collection uses schema validation and has validationAction set to error, inserting an invalid document or updating a document with invalid values with $merge throws a MongoServerError and the document is not written to the target collection. If there are multiple invalid documents, only the first invalid document encountered throws an error. All valid documents are written to the target collection, and all invalid documents fail to write.
whenMatched Pipeline Behavior
$merge inserts the document directly into the output collection when all of the following are true:
The value of whenMatched is an aggregation pipeline.
The value of whenNotMatched is
insert.There is no match for a document in the output collection.
$merge and $out Comparison
With the introduction of $merge, MongoDB provides two stages, $merge and $out, for writing the results of the aggregation pipeline to a collection:
$merge | |
|---|---|
|
|
|
|
|
|
|
|
|
|
Output to the Same Collection that is Being Aggregated
Warning
When $merge outputs to the same collection that is being aggregated, documents may get updated multiple times or the operation may result in an infinite loop. This behavior occurs when the update performed by $merge changes the physical location of documents stored on disk. When the physical location of a document changes, $merge may view it as an entirely new document, resulting in additional updates. For more information on this behavior, see Halloween Problem.
$merge can output to the same collection that is being aggregated. You can also output to a collection which appears in other stages of the pipeline, such as $lookup.
Restrictions
Restrictions | Description |
|---|---|
An aggregation pipeline cannot use | |
An aggregation pipeline cannot use | |
view definition | A view definition cannot include the |
|
|
|
|
|
|
| The |