13

I need an example to implement transactions in MongoDB with GoLang.

I'm using this golang driver for mongodb

https://github.com/mongodb/mongo-go-driver

There is no clear documentation for how to implement transactions.

Can anyone help me?

Sreenath
  • 480
  • 2
  • 6
  • 17

2 Answers2

28

It can be confusing. Below is a simple example.

if session, err = client.StartSession(); err != nil {
    t.Fatal(err)
}
if err = session.StartTransaction(); err != nil {
    t.Fatal(err)
}
if err = mongo.WithSession(ctx, session, func(sc mongo.SessionContext) error {
    if result, err = collection.UpdateOne(sc, bson.M{"_id": id}, update); err != nil {
        t.Fatal(err)
    }
    if result.MatchedCount != 1 || result.ModifiedCount != 1 {
        t.Fatal("replace failed, expected 1 but got", result.MatchedCount)
    }

    if err = session.CommitTransaction(sc); err != nil {
        t.Fatal(err)
    }
    return nil
}); err != nil {
    t.Fatal(err)
}
session.EndSession(ctx)

You can view full examples here.

simagix
  • 1,832
  • 1
  • 9
  • 11
12

This will help you

ctx := context.Background()
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
    panic(err)
}

db := client.Database("testdb")
defer db.Client().Disconnect(ctx)
col := db.Collection("testcol")

// transaction
err = db.Client().UseSession(ctx, func(sessionContext mongo.SessionContext) error {
    err := sessionContext.StartTransaction()
    if err != nil {
        return err
    }

    _, err = col.InsertOne(sessionContext, bson.M{"_id": "1", "name": "berry"})
    if err != nil {
        return err
    }

    _, err = col.InsertOne(sessionContext, bson.M{"_id": "2", "name": "gucci"})
    if err != nil {
        sessionContext.AbortTransaction(sessionContext)
        return err
    }
    if err = session.CommitTransaction(sessionContext); err != nil {
        return err
    }
    return nil
})
Branislav Lazic
  • 14,388
  • 8
  • 60
  • 85
berryberry
  • 121
  • 1
  • 3
  • 1
    Why are you only aborting the transaction when the second operation fails, why not also when the first operation throws an error? @berryberry – Aayush Taneja Aug 29 '19 at 17:20
  • I agree with your point @AayushTaneja, but then we will have to use `if else` clause every time we interact with the database OR we just have to `CommitTransaction` in the last line? I think we just have to `CommitTransaction` in last line. Please correct me – Muhammad Tariq Feb 11 '21 at 04:41
  • This is the cleanest solution for sure - awesome :-). The mongo devs have added some help docs that changes your solution a little. [See the example block here](https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo#Client.UseSessionWithOptions) - `sessionContext.AbortTransaction(sessionContext)` should be `sessionContext.AbortTransaction(context.Background())` ensuring that the abort completes even if the context passed to session is shutting down or a timeout occurs during the session call. `session.CommitTransaction(sessionContext)` -> `sessionContext.CommitTransaction(context.Background())`. – TopherGopher Nov 16 '22 at 19:47