为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用mongodb/mongo-go-driver进行高效分页

如何使用mongodb/mongo-go-driver进行高效分页

Go
浮云间 2023-04-17 16:35:01
_id我在下面的文章中读到,使用 的自然顺序执行分页效率更高,因为 skip 总是从集合的开头开始。MongoDB 中快速高效的分页// Page 1db.students.find().limit(10)// Page 2last_id = ...  # logic to get last_iddb.students.find({'_id': {'$gt': last_id}}).limit(10)但我不知道如何使用mongodb/mongo-go-driver.
查看完整描述

3 回答

?
猛跑小猪

TA贡献1858条经验 获得超8个赞

你可以创建一个新的函数,不要忘记传递 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


查看完整回答
反对 回复 2023-04-17
?
慕慕森

TA贡献1856条经验 获得超17个赞

如果不需要分页,则设置 page=0 和 limit=0。


func GetUsers (page, limit int) {

    filter := bson.D{{}} // selects all documents

    options := new(options.FindOptions)

    if limit != 0 {

        if page == 0 {

            page = 1

        }

        options.SetSkip(int64((page - 1) * limit))

        options.SetLimit(int64(limit))

    }


    cursor, err := mongoCollection.Find(context.TODO(), filter, options)

...

}


查看完整回答
反对 回复 2023-04-17
?
潇潇雨雨

TA贡献1833条经验 获得超4个赞

cursor.skip ()方法要求服务器从输入结果集的开头开始扫描,然后才开始返回结果。随着偏移量的增加,cursor.skip() 会变慢。虽然范围查询可以使用索引来避免扫描不需要的文档,但与用于cursor.skip()分页相比,随着偏移量的增加,通常会产生更好的性能。

使用当前版本的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用另一个索引字段替换该字段。


查看完整回答
反对 回复 2023-04-17
  • 3 回答
  • 0 关注
  • 180 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信