How to use Azure Cosmos DB with Golang using MongoDB’s official Go driver
Azure Cosmos DB is a globally distributed multi-mode database service that scales easily. It is flexible and simple to get set up, making it a great choice for your next project.
Golang (also referred to as Go) is a statically typed, hyper performant language from Google which is making waves because of it’s perfect suitability to create micro-services with.
I wanted to work with the two together but found that the documentation encouraged the use of a community driver that is no longer maintained or accepting pull requests. There is a supported fork of the community driver but it has a lot of open pull requests and I worry that it may fall to the same fate as the original.
We can communicate with Azure Cosmos DB using the Azure Cosmos DB API for MongoDB. MongoDB is one of the most popular document databases around and Azure Cosmos DB supports an API that is compatible with MongoDB’s wire protocol. MongoDB has native support for Golang with an officially supported Golang driver. I wanted to use this official driver so that I could rely on the support of the good people at MongoDB that have done a great job keeping it up to date.
How to use the official MongoDB Golang Driver with Azure Cosmos DB
I’ll walk you through the process step by step but if you want to jump straight to the code and see how you can connect to Azure Cosmos DB using the official MongoDB Golang driver then you can find it in this Github repository.
Prerequisites
- An Azure subscription. If you don’t have an Azure subscription, create a free account before you begin.
- Alternatively, you can Try Azure Cosmos DB for free without an Azure subscription, free of charge and commitments. Or you can use the Azure Cosmos DB Emulator for this tutorial
- Go and a basic knowledge of the Go language.
- An IDE — GoLand by Jetbrains, Visual Studio Code by Microsoft, or Atom. In this tutorial, I’m using Atom.
Create a database account
- In a new window, sign in to the Azure portal.
2. In the left menu, click Create a resource, click Databases, and then under Azure Cosmos DB, click Create.
3. In the Create Azure Cosmos DB Account page, enter the settings for the new Azure Cosmos DB account.
Select Review+Create. You can skip the Network and Tags section.
4. The account creation takes a few minutes. Wait for the portal to display the Congratulations! Your Cosmos account with wire protocol compatibility for MongoDB is ready page.
Clone the sample application
Clone the sample application and install the required packages.
- Run the following command using a terminal window to download the official MongoDB driver for Golang
go get github.com/mongodb/mongo-go-driver
- Run the following command to get the example code
go get github.com/TheRegan/golang-azure-cosmosdb
Update your connection string
Now go back to the Azure portal to get your connection string information and copy it into the app.
- Click Quick start in the left navigation menu, and then click Other to view the connection string information required by the Go application.
- In Golang, open the main.go file in the GOROOT\src\github.com\The_Regan\golang-azure-cosmosdb directory and update the following lines of code using the connection string information from the Azure portal as shown in the following screenshot.
- The Database name is the prefix of the Host value in the Azure portal connection string pane. For the account shown in the image below, the Database name is cdbmongo2.
database = "The prefix of the Host value in the Azure portal"
username = "The Username in the Azure portal"
password = "The Password in the Azure portal"
4. Save the main.go file.
Review the code
This step is optional. If you’re interested in learning how the database resources are created in the code, you can review the following snippets. Otherwise, you can skip ahead to Run the App.
The following snippets are all taken from the main.go file.
Connecting the Go app to Cosmos DB
In order to connect we need to create a context and construct a URI to use with the connection. You can read more about contexts here. Then we use the Connect method to return a client that we can use to interact with our data.
//Create a context to use with the connection
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)//Create the URI we will use to connect to out cosmosDB
connecturi := fmt.Sprintf(
"mongodb://%s:%s@%s.documents.azure.com:10255/?ssl=true",
username,
password,
database)//Connect to the DB
client, err := mongo.Connect(ctx, options.Client().ApplyURI(connecturi))//Check for any errors
if err != nil {
log.Fatal(err)
}
Once we have the client we can ping the database to ensure the connection is ready to use before inserting or reading data
//Ping the DB to confirm the connection
err = client.Ping(ctx, nil)//Check for any errors
if err != nil {
log.Fatal(err)
}//Print confirmation of connection
fmt.Println("Connected to MongoDB!")
Now that we’re connected we can create a collection to store our documents in. Collections in MongoDB are synonymous with containers in Azure Cosmos DB. You can read more about them here.
collection := client.Database(database).Collection("player")
Create a document
We can create documents from structs or by creating bson inline and thhen insert them using the InsertOne method
//Create an example player
jackie := Player{
FirstName: "Jackie",
LastName: "Robinson",
Bats: "Right",
Throws: "Right",
Position: "2B",
Weight: 200,
HeightFeet: 5,
HeightInches: 11}//Insert the example player into our cosmosDB
res, err := collection.InsertOne(ctx, jackie)
fmt.Println("Inserted a single document from a struct: ", res.InsertedID)//We can also add documents inline:
res, err = collection.InsertOne(ctx, bson.M{
"firstname": "Joe",
"lastname": "Carter",
"bats": "Right",
"throws": "Right",
"position": "OF",
"weight": 215,
"heightfeet": 6,
"heightinches": 3})fmt.Println("Inserted a single document by constructing BSON: ", res.InsertedID)
Or we can use the InsertMany method to insert multiple documents in a single call
//Or insert many records:
albert := Player{
FirstName: "Albert",
LastName: "Pujols",
Bats: "Right",
Throws: "Right",
Position: "1B",
Weight: 235,
HeightFeet: 6,
HeightInches: 3}babe := Player{
FirstName: "Babe",
LastName: "Ruth",
Bats: "Left",
Throws: "Left",
Position: "OF",
Weight: 215,
HeightFeet: 6,
HeightInches: 2}players := []interface{}{albert, babe}manyres, err := collection.InsertMany(ctx, players)
if err != nil {
log.Fatal(err)
}fmt.Println("Inserted multiple documents: ", manyres.InsertedIDs)
Query or read a document
We can find a single document in our database using the FindOne method
//Retrieve a single document from our cosmosDB
var result Playererr = collection.FindOne(ctx, bson.D{{"lastname", "Robinson"}}).Decode(&result)
if err != nil {
log.Fatal(err)
}fmt.Println(
"Found result.\nName: ", result.FirstName, result.LastName,
"\nBats: ", result.Bats,
"\nThrows: ", result.Throws)
Or we can retrieve multiple results using the Find method
//Setup our options
opts := options.Find()
opts.SetLimit(2)//create a filter - thus will find all players of postion "OF"
fil := bson.D{{"position", "OF"}}//get a cursor which we can use to iterate through the results
cur, err := collection.Find(ctx, fil, opts)
if err != nil {
log.Fatal(err)
}//Initialise an iterator
i := 1fmt.Println("\nFound multiple results:")//iterate over results and print them to the screen
for cur.Next(ctx) {
//create a variable that we can decode our document into
var p Player
err := cur.Decode(&p)
if err != nil {
log.Fatal(err)
} fmt.Println(
"Result ", i,
":\nName: ", p.FirstName, p.LastName,
"\nBats: ", p.Bats,
"\nThrows: ", p.Throws)
i++
}if err := cur.Err(); err != nil {
log.Fatal(err)
}//Close the cursor when we're Finished
cur.Close(ctx)
Update a document
We can update a document using the UpdateOne method and the $set update operator. You can read about other update operators here.
f := bson.D{{"position", "2B"}}u := bson.D{
{"$set", bson.D{
{"position", "1B"},
}},
}ur, err := collection.UpdateOne(ctx, f, u)
if err != nil {
log.Fatal(err)
}
fmt.Println("Updated", ur.ModifiedCount, "players")
Delete a document
We can also delete a single document using the DeleteOne method
//Delete one
_, err = collection.DeleteOne(ctx, bson.D{{"lastname", "Pujols"}})
if err != nil {
log.Fatal(err)
}
fmt.Println("Deleted a single document")
Or delete many documents using a filter and the DeleteMany method
//Delete many
del, err := collection.DeleteMany(ctx, bson.D{{"bats", "Right"}})
if err !=nil {
log.Fatal(err)
}
fmt.Println("Deleted ", del.DeletedCount, "documents using delete many")
Close the connection
Once we’re done accessing our data we need to close the connection to thhe database
//Close the connection
err= client.Disconnect(ctx)
if err != nil {
log.Fatal(err)
} else {
fmt.Println("Connection closed")
}
Run the app
- Comment out the lines that delete the document, lines 217–229, so that you can see the documents after running the app.
- Navigate to the directory that the sample is in. From the gopath you can type the following in a terminal window to reach it:
cd src/github.com/TheRegan/golang-azure-cosmosdb
3. In a terminal window build the app by typing the following command:
go build
4. Run the app using go run:
go run main.go
5. You’ll see the results of the activity printed out to the console
Review your document in Data Explorer
Go back to the Azure portal to see your document in Data Explorer.
- Click Data Explorer (Preview) in the left navigation menu, expand your database, players, and then click Documents. In the Documents tab, click the _id to display the document in the right pane.
2. You can then work with the document inline and click Update to save it. You can also delete the document, or create new documents or queries
Review SLAs in the Azure portal
The Azure portal monitors your Cosmos DB account throughput, storage, availability, latency, and consistency. Charts for metrics associated with an Azure Cosmos DB Service Level Agreement (SLA) show the SLA value compared to actual performance. This suite of metrics makes monitoring your SLAs transparent.
To review metrics and SLAs:
- Select Metrics in your Cosmos DB account’s navigation menu.
- Select a tab such as Latency, and select a timeframe on the right. Compare the Actual and SLA lines on the charts.
3. Review the metrics on the other tabs.
Clean up resources
When you’re done with your web app and Azure Cosmos DB account, you can delete the Azure resources you created so you don’t incur more charges. To delete the resources:
- In the Azure portal, select Resource groups on the far left. If the left menu is collapsed, select
to expand it.
2. Select the resource group you created for this quickstart.
3. In the new window, select Delete resource group.
4. In the next window, type the name of the resource group to delete, and then select Delete.
Thanks for reading and I wish you all the best on your journey with Azure and Golang!