How To Store MongoDB Documents In A Slice And Iterate Over Them In Golang
Introduction to creating MongoDB queries and filters in Golang
If you’re working with MongoDB and Golang, it’s important to know how to create and format MongoDB filter queries so that they can be passed into method calls. Fortunately, this process is fairly simple and straightforward. In this article, we’ll show you how to create BSON map objects from raw JSON strings and from primitive.M
BSON objects. We’ll also explain how to pass these objects to the Golang driver’s method calls to query MongoDB documents.
Prerequisites for making API calls to MongoDB using the official Golang driver
Before we dive into the Golang code and learn how to make API calls to MongoDB, there are a few prerequisites that need to be reviewed:
MongoDB needs to be installed and running on the same server that’s making the Go API calls. You can type
mongod
in your terminal window to get information on the MongoDB daemon processes.You’ll need to have a few documents in a MongoDB collection that you can query in your Go script:
- If you’d like to access the attributes and fields of a Golang object, you’ll need to use a third-party library called oleiade/reflections, which returns high-level abstractions of Go’s native
reflect
library. To install this package, enter the following commands in your terminal or command prompt window:
- Golang also needs to be installed, and the MongoDB project directory needs to be in Go’s
$GOPATH
:
You can get information on the current value of GOPATH by using the commands go help gopath
or $GOPATH
. For more help with Go’s get
command, enter go help get
into a terminal window.
Import the MongoDB and Go packages in a Golang script
Now that we’ve gone over the prerequisites, we’re ready to turn to the code. We’ll start our script by importing the packages for MongoDB that can create BSON filters and queries and unmarshal strings in the main()
function:
import (
"context" // manage multiple requests
"encoding/json" // Use JSON encoding for bson.M string
"fmt" // Println() function
"log"
"reflect" // get an object type
// import 'mongo-go-driver' package libraries
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive" // for BSON ObjectID
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
Declare a new struct for the MongoDB document fields
We’ll use Golang’s struct
datatype to map the MongoDB fields for the collection’s documents:
Key string `json:"key,omitempty"`
// ObjectId() or objectid.ObjectID is deprecated--use primitive instead
ID primitive.ObjectID `bson:"_id, omitempty"`
// Use these field tags so Golang knows how to map MongoDB fields
// `bson:"string field" json:"string field"`
StringField string `bson:"string field" json:"string field"`
IntField int `bson:"int field" json:"int field"`
BoolField bool `bson:"bool field" json:"bool field"`
}
View a collection’s document fields in the Mongo Shell
If you’re not sure of the datatypes for a collection’s document fields, simply enter these commands in the Mongo Shell to view the exact format of the fields:
use SomeDatabase
db["Some Collection"]
db["Some Collection"].findOne()
Declare the Golang main() function and connect to MongoDB
Now we’ll declare the main()
function, which is necessary for the MongoDB API calls and document iteration. We can connect to the MongoDB server using mongo.Connect()
and have it return a client instance that will be used to get a collection’s documents:
// Declare host and port options to pass to the Connect() method
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
// Connect to the MongoDB and return Client instance
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
fmt.Println("mongo.Connect() ERROR:", err)
log.Fatal(err)
}
// Declare Context object for the MongoDB API calls
ctx := context.Background()
// Access a MongoDB collection through a database
col := client.Database("SomeDatabase").Collection("Some Collection")
When you’re adding this code to your script, be sure to replace the "SomeDatabase"
and "Some Collection"
strings shown in the example with the correct names for your MongoDB database and collection.
Declaring a BSON map MongoDB filter object
Next, we’ll nest a BSON query into another BSON map object which has one of the collection’s fields as its key:
Build a MongoDB filter query from a string in Golang
In this section, we’ll look at the process of creating a BSON map object from a string to use for a MongoDB query in Golang.
Declare a Go string containing a MongoDB JSON filter
We’ll use backticks to declare a raw string of a valid JSON object in Golang; this MongoDB JSON string in Golang will be used for the filter. Then, we’ll instantiate an empty bson.M
object for the unmarshaled data to be stored in:
query := `{"$eq":"last value"}`
// Declare an empty BSON Map object
var bsonMap bson.M
Unmarshal a Go string using the JSON package
After that, we’ll unmarshal our string and return a primitive.M
object:
err = json.Unmarshal([]byte(query), &bsonMap)
if err != nil {
log.Fatal("json.Unmarshal() ERROR:", err)
} else {
fmt.Println("bsonMap:", bsonMap)
fmt.Println("bsonMap TYPE:", reflect.TypeOf(bsonMap))
fmt.Println("BSON:", reflect.TypeOf(bson.M{"int field": bson.M{"$gt":42}}))
}
Declare a nested bson.M MongoDB filter from the primitive.M object returned by json.Unmarshal()
filter := bson.M{"string field": bsonMap}
Use the MongoDB filter to return a Cursor object and iterate over the documents
At this point, we’ll have the Golang driver’s Find()
method return a Cursor object. Then we’ll iterate over the documents by passing a context object to the cursor’s Next()
method:
cursor, err := col.Find(ctx, filter)
if err != nil {
log.Fatal("col.Find ERROR:", err)
}
// Print cursor object
fmt.Println("\ncursor TYPE:", reflect.TypeOf(cursor))
fmt.Println("cursor:", cursor)
// iterate through all documents
for cursor.Next(ctx) {
var p MongoFields
// Decode the document
if err := cursor.Decode(&p); err != nil {
log.Fatal("cursor.Decode ERROR:", err)
}
// Print the results of the iterated cursor object
fmt.Printf("\nMongoFields: %+v\n", p)
}
}
Conclusion
Being able to construct filter queries is essential if you want to harness the power of MongoDB in your Golang scripts. Using strings and BSON map
objects, it’s easy to work with MongoDB filters in Golang. With the help of the examples provided in this tutorial, you’ll have a better understanding of how to create a MongoDB filter query using BSON in Golang.
Just the Code
We’ve looked at our code one section at a time so far. Shown below is the entire script used to query for MongoDB documents with BSON in Golang:
import (
"context" // manage multiple requests
"encoding/json" // Use JSON encoding for bson.M string
"fmt" // Println() function
"log"
"reflect" // get an object type
// import 'mongo-go-driver' package libraries
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive" // for BSON ObjectID
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type MongoFields struct {
Key string `json:"key,omitempty"`
// ObjectId() or objectid.ObjectID is deprecated--use primitive instead
ID primitive.ObjectID `bson:"_id, omitempty"`
// Use these field tags so Golang knows how to map MongoDB fields
// `bson:"string field" json:"string field"`
StringField string `bson:"string field" json:"string field"`
IntField int `bson:"int field" json:"int field"`
BoolField bool `bson:"bool field" json:"bool field"`
}
func main() {
// Declare host and port options to pass to the Connect() method
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
// Connect to the MongoDB and return Client instance
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
fmt.Println("mongo.Connect() ERROR:", err)
log.Fatal(err)
}
// Declare Context object for the MongoDB API calls
ctx := context.Background()
// Access a MongoDB collection through a database
col := client.Database("SomeDatabase").Collection("Some Collection")
// Typical BSON Map filter
//filter := bson.M{"int field": bson.M{"$gt":42}}
// Create a string using ` string escape ticks
query := `{"$eq":"last value"}`
// Declare an empty BSON Map object
var bsonMap bson.M
// Use the JSON package's Unmarshal() method
err = json.Unmarshal([]byte(query), &bsonMap)
if err != nil {
log.Fatal("json.Unmarshal() ERROR:", err)
} else {
fmt.Println("bsonMap:", bsonMap)
fmt.Println("bsonMap TYPE:", reflect.TypeOf(bsonMap))
fmt.Println("BSON:", reflect.TypeOf(bson.M{"int field": bson.M{"$gt": 42}}))
}
// Nest the Unmarshalled BSON map inside another BSON object
filter := bson.M{"string field": bsonMap}
// Pass the filter to Find() to return a MongoDB cursor
cursor, err := col.Find(ctx, filter)
if err != nil {
log.Fatal("col.Find ERROR:", err)
}
// Print cursor object
fmt.Println("\ncursor TYPE:", reflect.TypeOf(cursor))
fmt.Println("cursor:", cursor)
// iterate through all documents
for cursor.Next(ctx) {
var p MongoFields
// Decode the document
if err := cursor.Decode(&p); err != nil {
log.Fatal("cursor.Decode ERROR:", err)
}
// Print the results of the iterated cursor object
fmt.Printf("\nMongoFields: %+v\n", p)
}
}
Pilot the ObjectRocket Platform Free!
Try Fully-Managed CockroachDB, Elasticsearch, MongoDB, PostgreSQL (Beta) or Redis.
Get Started