Overview
在本指南中,可以了解如何使用游标访问数据。
游标是一种机制,允许应用程序遍历数据库结果,同时在给定时间内只在内存中保留其中的一个子集。匹配多个文档的读取操作会使用游标分批返回这些文档,而不是一次性返回所有文档。
示例游标
读取操作(如 Find() 方法)会返回引用与该操作匹配的文档的 Cursor。要获取游标,请首先连接到部署并访问集合,如以下示例所示:
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/zh-cn/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")
本指南中的示例使用以下 MyStruct 结构作为集合中文档的模型:
type MyStruct struct { MyProperty string }
以下代码将示例文档插入集合:
docs := []any{ MyStruct{MyProperty: "Beach House"}, MyStruct{MyProperty: "Office"}, MyStruct{MyProperty: "Bungalow"}, } result, err := coll.InsertMany(context.TODO(), docs) if err != nil { panic(err) }
要获取游标,请在集合上调用 Find() 方法来运行查询并返回游标。以下示例将空过滤器传递给集合中的所有文档,并将结果游标分配给 cursor 变量:
cursor, err := coll.Find(context.TODO(), bson.D{}) if err != nil { panic(err) }
本指南的每个部分都使用此 cursor 变量。驱动程序将游标引用的文档解组合到 MyStruct 结构。
重要
游标并不具备 goroutine 安全性。请勿在多个 goroutine 中同时使用同一游标。
分别检索文档
要在阻止当前 goroutine 的同时从游标单独检索文档,请使用 Next() 方法。
如果满足所有以下条件,该方法返回一个文档:
当前已提供或稍后会提供文档。
驱动程序没有报告任何错误。
上下文未过期。
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) }
可追加游标
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.
如果满足所有以下条件,该方法返回一个文档:
当前有文档可供使用。
驱动程序没有报告任何错误。
上下文未过期。
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 } }
检索所有文档
要使用所有查询结果填充切片,请使用 All() 方法:
var results []MyStruct if err := cursor.All(context.TODO(), &results); err != nil { panic(err) } for _, result := range results { fmt.Printf("%+v\n", result) }
重要
内存
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() 方法关闭游标。此方法能够释放游标在客户端应用程序和 MongoDB 服务器中消耗的资源。
defer cursor.Close(context.TODO())
注意
When you retrieve documents individually by using the Next() or TryNext() method, always close the cursor to free the resources that it consumes.
更多信息
要了解有关本指南中讨论的操作的更多信息,请参阅以下指南:
API 文档
如需进一步了解游标以及如何访问游标元素,请参阅以下 API 文档: