Как использовать mongodb / mongo-go-driver для эффективной подкачки страниц - PullRequest
0 голосов
/ 06 октября 2018

В следующей статье я прочитал, что более эффективно использовать естественное упорядочение _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.

1 Ответ

0 голосов
/ 08 октября 2018

Метод cursor.skip () требует, чтобы сервер сканировал с начала набора входных результатов, прежде чем начать возвращать результаты.По мере увеличения смещения cursor.skip () станет медленнее.В то время как запросы диапазона могут использовать индексы, чтобы избежать сканирования нежелательных документов, обычно это приводит к повышению производительности при увеличении смещения по сравнению с использованием cursor.skip() для разбивки на страницы.См. Дополнительную информацию по MongoDB: Пример нумерации страниц

Использование текущей версии mongo-go-driver (v0.0.15). Пример выполнения нумерации страниц с отображением последней записи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
}

Пример вызова функции разбивки на страницы выше:

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 другим индексированным полем.

...