skip to Main Content

I’m looking for way to execute multiple statement in mongodb in a transaction. All or nothing kind of scenario. To make it easy to understand

trxTest> db.users.find({})
[ { _id: ObjectId("64ad882f451d9a5fc930eeb7"), name: 'werain' } ]
trxTest>

I’m looking to insert the multiple documents and one of the document conflict the uniquenss key on name ‘werain’

    client, err := mongo.Connect(context.Background(), options.Client().ApplyURI("mongodb://localhost:27017"))
    if err != nil {
        panic(err)
    }
    DB := client.Database("trxTest")
    coll1 := DB.Collection("users")

    session, err := client.StartSession()
    if err != nil {
        panic(err)
    }

    defer session.EndSession(context.Background())

    _, err = session.WithTransaction(context.Background(), func(ctx mongo.SessionContext) (interface{}, error) {
        _, err = coll1.InsertOne(context.Background(), bson.M{"name": "vikas"})
        if err != nil {
            return nil, err
        }

        fmt.Println("vikas is inserted")


        _, err = coll1.InsertOne(context.Background(), bson.M{"name": "sriram"})
        if err != nil {
            return nil, err
        }
        fmt.Println("sriram is inserted")

        fmt.Println("inserting is werain again")
        _, err = coll1.InsertOne(context.Background(), bson.M{"name": "werain"}) // This is where the transaction should failed
        if err != nil {
            return nil, err
        }
        fmt.Println("werain is inserted")
        return nil, nil
    }, nil)

   
    if err != nil {
        fmt.Println("got trx error", err)
    }

Here how the code looks
I was accepting the database would rollback my 2 entry for users with name "vikas" and "sriram"

but I see this

trxTest> db.users.find({})
[
  { _id: ObjectId("64ad882f451d9a5fc930eeb7"), name: 'werain' },
  { _id: ObjectId("64ad8c65f63f3f2b48f66169"), name: 'vikas' },
  { _id: ObjectId("64ad8c66f63f3f2b48f6616a"), name: 'sriram' }
]

Error

vikas is inserted
sriram is inserted
inserting is werain again

got error write exception: write errors: [E11000 duplicate key error collection: trxTest.users index: name_1 dup key: { name: "werain" }]
db version v6.0.1
Build Info: {
    "version": "6.0.1",
    "gitVersion": "32f0f9c88dc44a2c8073a5bd47cf779d4bfdee6b",
    "modules": [],
    "allocator": "system",
    "environment": {
        "distarch": "aarch64",
        "target_arch": "aarch64"
    }
}

2

Answers


  1. As pointed out by @burak-serdar, Transaction numbers are only allowed on a replica set member or mongos. See also PyMongo transaction error:Transaction numbers are only allowed on a replica set member or mongos.

    Besides that, the doc for the WithTransaction method of the mongo.Session interface states that

    Inside the callback, the SessionContext must be used as the Context parameter for any operations that should be part of the transaction.

    So you should replace all the following calls

    _, err = coll1.InsertOne(context.Background(), //...
    

    with

    _, err = coll1.InsertOne(ctx, //...
    
    Login or Signup to reply.
  2. For this case, and not having access to Transactions (as pointed out by @Zeke Lu amd @Burak Serdar) your best option is to use a bulk operation like Insert Many

    This way, you’ll get a BulkWriteError for the duplicate _id key, but all the others should insert. For this to work, use an unordered insertMany operation.

    ordered operations stop after an error, while unordered operations continue to process any remaining write operations in the queue

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search