When I started to develop in Go I found that one of the things that sometimes is missing is the multitude of examples on the net like you would find with NodeJS. I am not saying that Go is not popular, all I am saying is that sometimes I wish there were more examples out there. This is especially true for the mongo-go-driver. That is why I decided to write this post.
This is a very short post just to show you how to use the findOneAndUpdate
function from the official mongodb driver for Go.
The mongo-go-driver is the official driver for mongo for Go. It is developed by the mongodb team and is what you would use today to perform any CRUD operations on mongodb from your Go application.
There are several really good blog posts out there, especially the ones from the mongodb team. Here are a few just in case you didn’t come across them yourself. This is the getting started with Go tutorial and it’s extremely good.
Also if you have been using a community driver like mgo here is a post regarding migration steps to the official mongo driver.
And finally here is the official Go Doc for the driver.
All the examples and tutorials I found seem to focus solely on the default and most commonly used functions in the driver.
In the past when using mongodb with NodeJS I made heavy use of Mongoose.js and usually in my REST API’s I like to return any newly created resources to facilitate the client, thus avoiding that a client has to perform a subsequent GET request after updating a resource.
To do so I make use of the findOneAndUpdate
function when I need to update a resource, and so it is natural for me to do so even when using Go. Unfortunately none of the tutorials out there show you how to use this function.
Below is a very simple example to illustrate how to use FindOneAndUpdate
using the mongo-go-driver.
package main
import (
"context"
"fmt"
"log"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func findOneAndUpdate(url string, db string, coll string) (bson.M, error) {
// 1) Create the context
exp := 5*time.Second
ctx, cancel := context.WithTimeout(context.Background(), exp)
defer cancel()
// 2) Create the connection
conn, err := mongo.Connect(ctx, options.Client().ApplyURI(url))
if err != nil {
log.Fatal(err.Error())
}
// 2) Select the database
database := conn.Database(db)
// 4) Select the collection
collection := database.Collection(coll)
// 5) Create the search filter
filter := bson.M{"name": "luke"}
// 6) Create the update
update := bson.M{
"$set": bson.M{"lastname": "skywalker"},
}
// 7) Create an instance of an options and set the desired options
upsert := true
after := options.After
opt := options.FindOneAndUpdateOptions{
ReturnDocument: &after,
Upsert: &upsert,
}
// 8) Find one result and update it
result := collection.FindOneAndUpdate(ctx, filter, update, &opt)
if result.Err() != nil {
return nil, result.Err()
}
// 9) Decode the result
doc := bson.M{}
decodeErr := result.Decode(&doc)
return doc, decodeErr
}
And you can call the function like so
package main
func main() {
url := "mongodburl"
db := "jedi"
coll := "characters"
doc, err := findOneAndUpdate(url, db, coll)
if err != nil {
fmt.Printf("Error: %s", err.Error())
}
fmt.Printf("%+v", doc)
}
The FindOneAndUpdateOptions
struct allows you to choose several different options.
As you can see from the code above I have set the options to return document after the update and to run an upsert in case the document is not found in the collection.
For more information about the possible options feel free to browse the the mongo options
package. You will see that the FindOneAndUpdateOptions
struct is defined as such.
// From the official mongo-go-driver source code.
type FindOneAndUpdateOptions struct {
ArrayFilters *ArrayFilters
BypassDocumentValidation *bool
Collation *Collation
MaxTime *time.Duration
Projection interface{}
ReturnDocument *ReturnDocument
Sort interface{}
Upsert *bool
}
Here are the links to the official mongo-go-driver source code and relative documentation
Also, here is the link to a working example. Please feel free to test the code.