栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

使用mgo在MongoDB中进行有效的分页

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用mgo在MongoDB中进行有效的分页

不幸的是,

mgo.v2
驱动程序没有提供API调用来指定
cursor.min()

但是有一个解决方案。该

mgo.Database
类型提供了
Database.Run()
一种运行任何MongoDB命令的方法。可在此处找到可用的命令及其文档:数据库命令

从MongoDB
3.2开始,提供了一个新

find
命令,该命令可用于执行查询,并且支持指定
min
表示第一个索引条目的参数,该索引条目开始列出结果。

好。我们需要做的是在每批(一页

min
文档)从查询结果的最后一个文档生成文档之后,该文档必须包含用于执行查询的索引条目的值,然后是下一个批次(可以通过在执行查询之前设置此最小索引条目来获取下一页的文档)。

该索引条目(从现在开始将其称为 光标) 可以被编码为a

string
并与结果一起发送给客户端,并且当客户端想要下一页时,他会发回 光标,
说他想要从该光标之后开始的结果。

手动执行(“硬”方式)

要执行的命令可以采用不同的形式,但是命令名称(

find
)必须在经过编组的结果中位于第一个位置,因此我们将使用
bson.D
(与相比保留了顺序
bson.M
):

limit := 10cmd := bson.D{    {Name: "find", Value: "users"},    {Name: "filter", Value: bson.M{"country": "USA"}},    {Name: "sort", Value: []bson.D{        {Name: "name", Value: 1},        {Name: "_id", Value: 1},    },    {Name: "limit", Value: limit},    {Name: "batchSize", Value: limit},    {Name: "singleBatch", Value: true},}if min != nil {    // min is inclusive, must skip first (which is the previous last)    cmd = append(cmd,        bson.DocElem{Name: "skip", Value: 1},        bson.DocElem{Name: "min", Value: min},    )}

可以使用以下类型捕获执行MongoDB

find
命令的结果
Database.Run()

var res struct {    OK       int `bson:"ok"`    WaitedMS int `bson:"waitedMS"`    Cursor   struct {        ID         interface{} `bson:"id"`        NS         string      `bson:"ns"`        FirstBatch []bson.Raw  `bson:"firstBatch"`    } `bson:"cursor"`}db := session.DB("")if err := db.Run(cmd, &res); err != nil {    // Handle error (abort)}

现在,我们得到结果,但类型为

[]bson.Raw
。但是我们希望它是type的一部分
[]*User
。这是
Collection.NewIter()
方便的地方。它可以将类型的值转换(解组)为
[]bson.Raw
我们通常传递给
Query.All()
或的任何类型
Iter.All()
。好。让我们来看看它:

firstBatch := res.Cursor.FirstBatchvar users []*Usererr = db.C("users").NewIter(nil, firstBatch, 0, nil).All(&users)

现在,我们有了下一页的用户。只剩下一件事了:如果需要,生成用于获取下一页的游标:

if len(users) > 0 {    lastUser := users[len(users)-1]    cursordata:= []bson.D{        {Name: "country", Value: lastUser.Country},        {Name: "name", Value: lastUser.Name},        {Name: "_id", Value: lastUser.ID},    }} else {    // No more users found, use the last cursor}

一切都很好,但是我们如何将a转换

cursorData
string
,反之亦然?我们可能会使用
bson.Marshal()
bson.Unmarshal()
用base64编码相结合;
的使用
base64.RawURLEncoding
将为我们提供一个网络安全的游标字符串,可以将其添加到URL查询中而不进行转义。

这是一个示例实现:

// CreateCursor returns a web-safe cursor string from the specified fields.// The returned cursor string is safe to include in URL queries without escaping.func CreateCursor(cursorData bson.D) (string, error) {    // bson.Marshal() never returns error, so I skip a check and early return    // (but I do return the error if it would ever happen)    data, err := bson.Marshal(cursorData)    return base64.RawURLEncoding.EnpreToString(data), err}// ParseCursor parses the cursor string and returns the cursor data.func ParseCursor(c string) (cursorData bson.D, err error) {    var data []byte    if data, err = base64.RawURLEncoding.DepreString(c); err != nil {        return    }    err = bson.Unmarshal(data, &cursorData)    return}

最后,我们有了高效但不那么短的MongoDB

mgo
分页功能。继续阅读…

使用
github.com/icza/minquery
(“简单”方式)

手动方式相当冗长;它可以 通用自动化
。这就是

github.com/icza/minquery
图片所在的位置(
披露:我是作者 )。它提供了一个包装器来配置和执行MongoDB
find
命令,允许您指定一个游标,并且在执行查询后,它会返回给您新的游标,以用于查询下一批结果。包装器的
MinQuery
类型非常相似,
mgo.Query
但是它支持
min
通过
MinQuery.Cursor()
方法指定MongoDB的类型。

上面使用的解决方案

minquery
如下所示:

q := minquery.New(session.DB(""), "users", bson.M{"country" : "USA"}).    Sort("name", "_id").Limit(10)// If this is not the first page, set cursor:// getLastCursor() represents your logic how you acquire the last cursor.if cursor := getLastCursor(); cursor != "" {    q = q.Cursor(cursor)}var users []*UsernewCursor, err := q.All(&users, "country", "name", "_id")

就这样。

newCursor
是用于获取下一批的光标。

注意#1: 调用时

MinQuery.All()
,必须提供游标字段的名称,这将用于从中构建游标数据(最终是游标字符串)。

注意#2:
如果您要检索部分结果(使用

MinQuery.Select()
),则即使您不打算直接使用它们,也必须包括所有属于光标的字段(索引条目),否则
MinQuery.All()
就不会游标字段的所有值,因此它将无法创建正确的游标值。

minquery
此处查看打包文档:https :
//godoc.org/github.com/icza/minquery,它很短,希望可以清理。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/365546.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号