我在下一篇文章中读到,使用_id
的自然顺序执行分页会更有效,因为跳过总是从集合的开头开始
https://www.codementor.io/arpitbhayani/fast-and-efficient-pagination-in-mongodb-9095flbqr
// Page 1
db.students.find().limit(10)
// Page 2
last_id = ... # logic to get last_id
db.students.find({'_id': {'$gt': last_id}}).limit(10)
但是我不知道如何使用mongodb/mongo-go-driver
执行上述操作。
答案 0 :(得分:0)
cursor.skip()方法要求服务器从输入结果集的开头开始扫描,然后再开始返回结果。随着偏移量的增加,cursor.skip()会变慢。尽管范围查询可以使用索引来避免扫描不需要的文档,但是与使用cursor.skip()
进行分页相比,随着偏移量的增加,通常可以产生更好的性能。查看有关MongoDB: Pagination Example
使用mongo-go-driver(v0.0.15)的当前版本。执行分页的示例首先显示最新条目:
func Paginate(collection *mongo.Collection, startValue objectid.ObjectID, nPerPage int64) ([]bson.Document, *bson.Value, error) {
// Query range filter using the default indexed _id field.
filter := bson.VC.DocumentFromElements(
bson.EC.SubDocumentFromElements(
"_id",
bson.EC.ObjectID("$gt", startValue),
),
)
var opts []findopt.Find
opts = append(opts, findopt.Sort(bson.NewDocument(bson.EC.Int32("_id", -1))))
opts = append(opts, findopt.Limit(nPerPage))
cursor, _ := collection.Find(context.Background(), filter, opts...)
var lastValue *bson.Value
var results []bson.Document
for cursor.Next(context.Background()) {
elem := bson.NewDocument()
err := cursor.Decode(elem)
if err != nil {
return results, lastValue, err
}
results = append(results, *elem)
lastValue = elem.Lookup("_id")
}
return results, lastValue, nil
}
调用上述分页功能的示例:
database := client.Database("databaseName")
collection := database.Collection("collectionName")
startObjectID, _ := objectid.FromHex("5bbafea2b5e14ee3a298fa4a")
// Paginate only the latest 20 documents
elements, lastID, err := Paginate(collection, startObjectID, 20)
for _, e := range elements {
fmt.Println(&e)
}
// Last seen ObjectID can be used to call next Paginate()
fmt.Println("Last seen ObjectID: ", lastID.ObjectID())
请注意,您也可以将_id
字段替换为另一个索引字段。
答案 1 :(得分:0)
您可以创建一个新的函数,不要忘记传递http.writer来读取参数。
func Pagination(r *http.Request, FindOptions *options.FindOptions) (int64, int64) {
if r.URL.Query().Get("page") != "" && r.URL.Query().Get("limit") != "" {
page, _ := strconv.ParseInt(r.URL.Query().Get("page"), 10, 32)
limit, _ := strconv.ParseInt(r.URL.Query().Get("limit"), 10, 32)
if page == 1 {
FindOptions.SetSkip(0)
FindOptions.SetLimit(limit)
return page, limit
}
FindOptions.SetSkip((page - 1) * limit)
FindOptions.SetLimit(limit)
return page, limit
}
FindOptions.SetSkip(0)
FindOptions.SetLimit(0)
return 0, 0
}
随便打电话
Pagination(r, options)
示例
options := options.Find()
page, limit := parameter.Pagination(r, options)
// page, limit as response for header payload