MongoDB Go Driver
High-performance MongoDB integration for Go applications
🐹 What is MongoDB Go Driver?
The MongoDB Go Driver provides idiomatic Go integration for MongoDB databases. It leverages Go's concurrency features, offers excellent performance, and follows Go conventions with context support, making it ideal for building scalable microservices and cloud-native applications.
// Simple Go connection
import "go.mongodb.org/mongo-driver/mongo"
client, _ := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
fmt.Println("Connected to MongoDB!")
Key Features
High Performance
Optimized for Go's concurrency model
Context Support
Native context.Context integration
Idiomatic Go
Follows Go best practices
Type Safety
Strong typing with BSON tags
🔹 Installation
Install the MongoDB Go Driver using Go modules. This package provides all necessary tools for connecting to MongoDB and performing database operations with full Go integration and concurrency support.
# Install using go get
go get go.mongodb.org/mongo-driver/mongo
# Or add to go.mod
go mod init myapp
go get go.mongodb.org/mongo-driver/mongo
🔹 Connecting to MongoDB
Establish a connection using mongo.Connect with context support. The driver manages connection pooling automatically and provides thread-safe access to databases and collections with proper error handling.
package main
import (
"context"
"fmt"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
// Create context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// Connect to MongoDB
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
log.Fatal(err)
}
defer client.Disconnect(ctx)
// Ping the database
err = client.Ping(ctx, nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to MongoDB!")
// Get database and collection
database := client.Database("myDatabase")
collection := database.Collection("users")
}
🔹 Define Structs
Create Go structs to represent MongoDB documents with BSON tags for field mapping. Use bson tags to control serialization and omitempty to exclude zero values, ensuring clean document storage.
import (
"go.mongodb.org/mongo-driver/bson/primitive"
"time"
)
type User struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
Name string `bson:"name"`
Email string `bson:"email"`
Age int `bson:"age"`
Hobbies []string `bson:"hobbies,omitempty"`
CreatedAt time.Time `bson:"created_at"`
}
// Constructor function
func NewUser(name, email string, age int) *User {
return &User{
Name: name,
Email: email,
Age: age,
Hobbies: []string{},
CreatedAt: time.Now(),
}
}
🔹 Insert Documents
Add documents to collections using Go structs. The driver provides InsertOne for single documents and InsertMany for bulk inserts, both returning detailed results including generated IDs.
import "go.mongodb.org/mongo-driver/bson/primitive"
// Insert one document
user := NewUser("John Doe", "[email protected]", 30)
user.Hobbies = []string{"reading", "coding"}
result, err := collection.InsertOne(ctx, user)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Inserted ID: %v\n", result.InsertedID)
// Insert multiple documents
users := []interface{}{
NewUser("Alice", "[email protected]", 25),
NewUser("Bob", "[email protected]", 35),
}
multiResult, err := collection.InsertMany(ctx, users)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Inserted %d documents\n", len(multiResult.InsertedIDs))
Output:
Inserted ID: ObjectID("507f1f77bcf86cd799439011")
Inserted 2 documents
🔹 Find Documents
Query collections using BSON filters for flexible data retrieval. Use Find for multiple documents with cursor iteration or FindOne for single documents, with full context support for timeouts and cancellation.
import "go.mongodb.org/mongo-driver/bson"
// Find all documents
cursor, err := collection.Find(ctx, bson.M{})
if err != nil {
log.Fatal(err)
}
defer cursor.Close(ctx)
var users []User
if err = cursor.All(ctx, &users); err != nil {
log.Fatal(err)
}
for _, user := range users {
fmt.Println(user.Name)
}
// Find with filter
filter := bson.M{"age": bson.M{"$gte": 18}}
cursor, err = collection.Find(ctx, filter)
// ... process results
// Find one document
var user User
err = collection.FindOne(ctx, bson.M{"name": "John Doe"}).Decode(&user)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found: %s\n", user.Name)
// Find with options (projection, sort, limit)
opts := options.Find().SetProjection(bson.M{"name": 1, "email": 1}).SetLimit(10)
cursor, err = collection.Find(ctx, bson.M{}, opts)
Output:
John Doe
Found: John Doe
🔹 Update Documents
Modify documents using BSON update operators. The driver supports UpdateOne for single documents and UpdateMany for bulk updates, returning detailed results about matched and modified documents.
import "go.mongodb.org/mongo-driver/bson"
// Update one document
filter := bson.M{"name": "John Doe"}
update := bson.M{
"$set": bson.M{
"age": 31,
"email": "[email protected]",
},
}
result, err := collection.UpdateOne(ctx, filter, update)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Modified: %d\n", result.ModifiedCount)
// Update many documents
filterMany := bson.M{"age": bson.M{"$lt": 30}}
updateMany := bson.M{"$set": bson.M{"status": "young"}}
multiResult, err := collection.UpdateMany(ctx, filterMany, updateMany)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Updated: %d\n", multiResult.ModifiedCount)
// Increment a value
incUpdate := bson.M{"$inc": bson.M{"age": 1}}
collection.UpdateOne(ctx, filter, incUpdate)
// Add to array
pushUpdate := bson.M{"$push": bson.M{"hobbies": "gaming"}}
collection.UpdateOne(ctx, filter, pushUpdate)
Output:
Modified: 1
Updated: 2
🔹 Delete Documents
Remove documents from collections using DeleteOne or DeleteMany. The driver returns detailed results including the count of deleted documents, allowing you to verify the operation's success.
import "go.mongodb.org/mongo-driver/bson"
// Delete one document
filter := bson.M{"name": "John Doe"}
result, err := collection.DeleteOne(ctx, filter)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Deleted: %d\n", result.DeletedCount)
// Delete many documents
filterMany := bson.M{"age": bson.M{"$lt": 18}}
multiResult, err := collection.DeleteMany(ctx, filterMany)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Deleted: %d\n", multiResult.DeletedCount)
// Delete all documents
deleteAll, err := collection.DeleteMany(ctx, bson.M{})
if err != nil {
log.Fatal(err)
}
fmt.Printf("All deleted: %d\n", deleteAll.DeletedCount)
Output:
Deleted: 1
Deleted: 3
🔹 Aggregation Pipeline
Build complex aggregation pipelines using BSON arrays and documents. Combine multiple stages like match, group, and sort to perform sophisticated data analysis directly in MongoDB with full Go type safety.
import "go.mongodb.org/mongo-driver/bson"
// Aggregation pipeline
pipeline := []bson.M{
{"$match": bson.M{"age": bson.M{"$gte": 18}}},
{"$group": bson.M{
"_id": "$city",
"avgAge": bson.M{"$avg": "$age"},
"count": bson.M{"$sum": 1},
}},
{"$sort": bson.M{"avgAge": -1}},
}
cursor, err := collection.Aggregate(ctx, pipeline)
if err != nil {
log.Fatal(err)
}
defer cursor.Close(ctx)
type Result struct {
City string `bson:"_id"`
AvgAge float64 `bson:"avgAge"`
Count int `bson:"count"`
}
var results []Result
if err = cursor.All(ctx, &results); err != nil {
log.Fatal(err)
}
for _, result := range results {
fmt.Printf("%s: avg %.1f, count %d\n", result.City, result.AvgAge, result.Count)
}
Output:
New York: avg 32.0, count 5
Boston: avg 28.0, count 3
🔹 Transactions
Execute multi-document transactions for ACID guarantees. Use sessions to group operations that must succeed or fail together, ensuring data consistency across multiple collections or databases.
import "go.mongodb.org/mongo-driver/mongo"
// Start a session
session, err := client.StartSession()
if err != nil {
log.Fatal(err)
}
defer session.EndSession(ctx)
// Execute transaction
err = mongo.WithSession(ctx, session, func(sc mongo.SessionContext) error {
// Start transaction
if err := session.StartTransaction(); err != nil {
return err
}
// Perform operations
_, err := collection.InsertOne(sc, NewUser("Test", "[email protected]", 25))
if err != nil {
session.AbortTransaction(sc)
return err
}
_, err = collection.UpdateOne(sc, bson.M{"name": "John"}, bson.M{"$inc": bson.M{"age": 1}})
if err != nil {
session.AbortTransaction(sc)
return err
}
// Commit transaction
return session.CommitTransaction(sc)
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Transaction completed successfully")
🔹 Error Handling
Implement robust error handling using Go's error interface and MongoDB-specific error types. Check for specific error conditions like duplicate keys, connection failures, or timeouts to build resilient applications.
import (
"go.mongodb.org/mongo-driver/mongo"
"errors"
)
func insertUser(ctx context.Context, collection *mongo.Collection, user *User) error {
_, err := collection.InsertOne(ctx, user)
if err != nil {
// Check for duplicate key error
if mongo.IsDuplicateKeyError(err) {
return errors.New("user with this email already exists")
}
// Check for timeout
if errors.Is(err, context.DeadlineExceeded) {
return errors.New("operation timed out")
}
// Check for network error
if mongo.IsNetworkError(err) {
return errors.New("network connection failed")
}
return fmt.Errorf("failed to insert user: %w", err)
}
return nil
}
// Usage
err := insertUser(ctx, collection, user)
if err != nil {
log.Printf("Error: %v\n", err)
}