Overview
In this guide, you can learn how to access data with a cursor.
A cursor is a mechanism that allows an application to iterate over database results while holding only a subset of them in memory at a given time. Read operations that match multiple documents use a cursor to return those documents in batches rather than all at once.
Sample Cursor
A read operation such as the Find() method returns a Cursor that references the documents matched by the operation. To obtain a cursor, first connect to your deployment and access a collection, as shown in the following example:
var uri string if uri = os.Getenv("MONGODB_URI"); uri == "" { log.Fatal("You must set your 'MONGODB_URI' environment variable. See\n\t https://www.mongodb.com/docs/drivers/go/current/usage-examples/") } client, err := mongo.Connect(options.Client().ApplyURI(uri)) if err != nil { panic(err) } defer func() { if err := client.Disconnect(context.TODO()); err != nil { panic(err) } }() coll := client.Database("db").Collection("sample_data")
The examples in this guide use the following MyStruct struct to model the documents in the collection:
type MyStruct struct { MyProperty string }
The following code inserts sample documents into the collection:
docs := []any{ MyStruct{MyProperty: "Beach House"}, MyStruct{MyProperty: "Office"}, MyStruct{MyProperty: "Bungalow"}, } result, err := coll.InsertMany(context.TODO(), docs) if err != nil { panic(err) }
To obtain a cursor, call the Find() method on the collection to run a query and return a cursor. The following example passes an empty filter to match all documents in the collection and assigns the resulting cursor to a cursor variable:
cursor, err := coll.Find(context.TODO(), bson.D{}) if err != nil { panic(err) }
Each section in this guide uses this cursor variable. The driver unmarshals the documents that the cursor references to the MyStruct struct.
Important
A cursor is not goroutine safe. Do not use the same cursor in multiple goroutines at the same time.
Retrieve Documents Individually
To retrieve documents from your cursor individually while blocking the current goroutine, use the Next() method.
The method returns a document if all of the following conditions are met:
A document is currently or will later be available.
The driver didn't throw any errors.
The context didn't expire.
for cursor.Next(context.TODO()) { var result MyStruct if err := cursor.Decode(&result); err != nil { log.Fatal(err) } fmt.Printf("%+v\n", result) } if err := cursor.Err(); err != nil { log.Fatal(err) }
Tailable Cursor
To attempt to retrieve a document without blocking the current goroutine, use the TryNext() method. Use this approach when you iterate over a tailable cursor.
The method returns a document if all of the following conditions are met:
A document is currently available.
The driver didn't throw any errors.
The context didn't expire.
for { if cursor.TryNext(context.TODO()) { var result MyStruct if err := cursor.Decode(&result); err != nil { log.Fatal(err) } fmt.Printf("%+v\n", result) continue } if err := cursor.Err(); err != nil { log.Fatal(err) } if cursor.ID() == 0 { break } }
Retrieve All Documents
To populate a slice with all of your query results, use the All() method:
var results []MyStruct if err := cursor.All(context.TODO(), &results); err != nil { panic(err) } for _, result := range results { fmt.Printf("%+v\n", result) }
{MyProperty:Beach House} {MyProperty:Office} {MyProperty:Bungalow}
Important
Memory
If the number and size of documents returned by your query exceeds available application memory, your program will crash. If you expect a large result set, you should consume your cursor iteratively.
Close the Cursor
When your application no longer requires a cursor, close the cursor with the Close() method. This method frees the resources your cursor consumes in both the client application and the MongoDB server.
defer cursor.Close(context.TODO())
Note
When you retrieve documents individually by using the Next() or TryNext() method, always close the cursor to free the resources that it consumes.
Additional Information
To learn more about the operations discussed in this guide, see the following guides:
API Documentation
To learn more about cursors and how to access their elements, see the following API Documentation: