Docs Menu

Docs HomeGo

Compound Operations

On this page

  • Overview
  • Find and Delete
  • Find and Update
  • Find and Replace
  • Additional Information

In this guide, you can learn how to perform compound operations.

Compound operations combine a read and write operation into a single operation. If you perform a read and write operation separately, there's a chance someone else may alter the document between both operations. MongoDB prevents this by placing a write lock on the document you are modifying for the duration of your compound operation.

MongoDB supports the following compound operations:

Tip

If you need to read and write to more than one document, use transactions.

The examples in this guide use the following Course struct as a model for documents in the courses collection:

type Course struct {
Title string
Enrollment int32
}

To run the examples in this guide, load the sample data into the db.courses collection with the following snippet:

coll := client.Database("db").Collection("courses")
docs := []interface{}{
Course{Title: "Representation Theory", Enrollment: 40},
Course{Title: "Early Modern Philosophy", Enrollment: 25},
Course{Title: "Animal Communication", Enrollment: 18},
}
result, err := coll.InsertMany(context.TODO(), docs)

Each document contains a description of a university course that includes the course title and maximum enrollment, corresponding to the title and enrollment fields in each document.

Tip

Non-existent Databases and Collections

If the necessary database and collection don't exist when you perform a write operation, the server implicitly creates them.

The FindOneAndDelete() method finds the first document that matches the specified query filter and deletes it. The method returns a SingleResult containing the deleted document.

Note

The FindOneAndDelete() method is an atomic operation, which means it prevents any other write operations from changing the matching document until it completes. The deleteOne() method is also an atomic operation, but differs from FindOneAndDelete() in that you cannot specify a sort order for the matched documents.

If you don't need to find and delete a document in a single transaction, you can call the findOne() method followed by the deleteOne() method.

You can modify the behavior of the FindOneAndDelete() method by passing in a FineOneAndDeleteOptions. If you don't specify a FineOneAndDeleteOptions, the driver uses the default values for each option.

The FineOneAndDeleteOptions type allows you to configure options with the following methods:

Method
Description
SetCollation()
The type of language collation to use when sorting results.
Default: nil
SetMaxTime()
The maximum amount of time that the query can run on the server.
Default: nil
SetProjection()
The fields to include in the document returned.
Default: nil
SetSort()
The sort fields and directions to order the documents matched.
Default: nil
SetHint()
The index to use to scan for documents.
Default: nil

The following example uses the FindOneAndDelete() method to match and delete the first document where the enrollment field value is less than 20:

filter := bson.D{{"enrollment", bson.D{{"$lt", 20}}}}
var deletedDoc Course
err := coll.FindOneAndDelete(context.TODO(), filter).Decode(&deletedDoc)
if err != nil {
panic(err)
}
res, _ := bson.MarshalExtJSON(deletedDoc, false, false)
fmt.Println(string(res))

The FindOneAndUpdate() method finds the first document that matches the specified query filter and updates it according to the update document. The method returns a SingleResult containing the matched document.

Note

The FindOneAndUpdate() method is an atomic operation, which means it prevents any other write operations from changing the matching document until it completes. The updateOne() method is also an atomic operation, but differs from FindOneAndUpdate() in that you cannot specify a sort order for the matched documents.

If you don't need to find and update a document in a single transaction, you can call the findOne() method followed by the updateOne() method.

You can modify the behavior of the FindOneAndUpdate() method by passing in a FineOneAndUpdateOptions. If you don't specify a FineOneAndUpdateOptions, the driver uses the default values for each option.

The FineOneAndUpdateOptions type allows you to configure options with the following methods:

Method
Description
SetArrayFilters()
The array elements the update applies to.
Default: nil
SetBypassDocumentValidation()
Whether to allow the write operation to opt-out of document level validation.
Default: false
SetCollation()
The type of language collation to use when sorting results.
Default: nil
SetMaxTime()
The maximum amount of time that the query can run on the server.
Default: nil
SetProjection()
The fields to include in the document returned.
Default: nil
SetReturnDocument()
Whether to return the original or updated document in the SingleResult.
Default: options.Before
SetSort()
The sort fields and directions to order the documents matched.
Default: nil
SetUpsert()
Whether to insert a new document if the query filter doesn't match any documents.
Default: false
SetHint()
The index to use to scan for documents.
Default: nil

The following example uses the FindOneAndUpdate() method to perform the following actions in order:

  • Matches the first document where the title field value includes "Modern"

  • Updates the matched document's enrollment field value to 32

  • Returns the updated document

filter := bson.D{{"title", bson.D{{"$regex", "Modern"}}}}
update := bson.D{{"$set", bson.D{{"enrollment", 32}}}}
opts := options.FindOneAndUpdate().SetReturnDocument(options.After)
var updatedDoc Course
err := coll.FindOneAndUpdate(context.TODO(), filter, update, opts).Decode(&updatedDoc)
if err != nil {
panic(err)
}
res, _ := bson.MarshalExtJSON(updatedDoc, false, false)
fmt.Println(string(res))

The FindOneAndReplace() method finds the first document that matches the specified query filter and replaces it with the replacement document. The method returns a SingleResult containing the matched document.

Note

This method differs from the ReplaceOne() method. FindOneAndReplace() performs a find and replace as a single operation, and eliminates the possibility of someone altering a document between both operations.

You can modify the behavior of the FindOneAndReplace() method by passing in a FineOneAndReplaceOptions. If you don't specify a FineOneAndReplaceOptions, the driver uses the default values for each option.

The FineOneAndReplaceOptions type allows you to configure options with the following methods:

Method
Description
SetBypassDocumentValidation()
Whether to allow the write operation to opt-out of document level validation.
Default: false
SetCollation()
The type of language collation to use when sorting results.
Default: nil
SetMaxTime()
The maximum amount of time that the query can run on the server.
Default: nil
SetProjection()
The fields to include in the document returned.
Default: nil
SetReturnDocument()
Whether to return the original or replaced document in the SingleResult.
Default: nil
SetSort()
The sort fields and directions to order the documents matched.
Default: nil
SetUpsert()
Whether to insert a new document if the query filter doesn't match any documents.
Default: false
SetHint()
The index to use to scan for documents.
Default: nil

The following example uses the FindOneAndReplace() method to perform the following actions in order:

  • Matches the first document where the title is "Representation Theory"

  • Replaces the matched document with a new document where the title is "Combinatorial Theory" and the enrollment is 35

filter := bson.D{{"title", "Representation Theory"}}
replacement := Course{Title: "Combinatorial Theory", Enrollment: 35}
var outdatedDoc Course
err := coll.FindOneAndReplace(context.TODO(), filter, replacement).Decode(&previousDoc)
if err != nil {
panic(err)
}
res, _ := bson.MarshalExtJSON(outdatedDoc, false, false)
fmt.Println(string(res))

To learn more about performing the operations mentioned, see the following guides:

To learn more about any of the methods or types discussed in this guide, see the following API Documentation:

←  Bulk OperationsModify Execution of CRUD Operations →