douwen4125 2018-10-06 09:49
浏览 838

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

I read in the following article that it is more efficient to use the natural ordering of _id to perform paging because skip always starts from the beginning from the collection

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)

But I have no idea how to perform the above using the mongodb/mongo-go-driver.

  • 写回答

1条回答 默认 最新

  • donglu9896 2018-10-08 12:21
    关注

    The cursor.skip() method requires the server to scan from the beginning of the input results set before beginning to return results. As the offset increases, cursor.skip() will become slower. While range queries can use indexes to avoid scanning unwanted documents, typically yielding better performance as the offset grows compared to using cursor.skip() for pagination. See more information on MongoDB: Pagination Example

    Using the current version of mongo-go-driver (v0.0.15).An example to perform pagination showing latest entry first:

    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
    }
    

    An example to call the pagination function above:

    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())
    

    Note that you can also substitute the _id field with another indexed field.

    评论

报告相同问题?

悬赏问题

  • ¥17 pro*C预编译“闪回查询”报错SCN不能识别
  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?