如何使用mongodb / mongo-go-driver执行有效的分页

时间:2018-10-06 09:49:49

标签: mongodb go mongodb-query

我在下一篇文章中读到,使用_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执行上述操作。

2 个答案:

答案 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