A go package for the mgo mongo driver (globalsign/mgo) and the official mongo driver mongodb/mongo-go-driver which ports the find functionality offered by the mongo-cursor-pagination node.js module. Also inspired by icza/minquery.
mongocursorpagination
helps implementing cursor based pagination in your mongodb backed service:
...where an API passes back a "cursor" (an opaque string) to tell the caller where to query the next or previous pages. The cursor is usually passed using query parameters next and previous...
mongocursorpagination
helps by providing a function that make it easy to query within a Mongo collection and returning a url-safe string that you can return with your HTTP response.
For this example we will be using an items mongo collection where items look like this:
Item struct {
ID bson.ObjectId `bson:"_id"`
Name string `bson:"name"`
CreatedAt time.Time `bson:"createdAt"`
}
Where the items collection is indexed:
mgo.Index{
Name: "cover_find_by_name",
Key: []string{
// _id is required in the index' key as we secondary sort on _id when the paginated field is not _id
Key: []string{"name", "_id"},
},
Unique: false,
Collation: &mgo.Collation{
Locale: "en",
Strength: 3,
},
Background: true,
}
The items store offers a method to find items (e.g. by name) and paginate the results using the find function exposed by mongocursorpagination
:
import "github.com/qlik-oss/mongocursorpagination/mgo"
...
// Find returns paginated items from the database matching the provided query
func (m *mongoStore) Find(query bson.M, next string, previous string, limit int, sortAscending bool, paginatedField string, collation mgo.Collation) ([]Item, mgocursor.Cursor, error) {
fp := mgocursor.FindParams{
Collection: m.col,
Query: query,
Limit: limit,
SortAscending: sortAscending,
PaginatedField: paginatedField,
Collation: &collation,
Next: next,
Previous: previous,
CountTotal: true,
}
var items []Item
c, err := mgocursor.Find(fp, &items)
cursor := mgocursor.Cursor{
Previous: c.Previous,
Next: c.Next,
HasPrevious: c.HasPrevious,
HasNext: c.HasNext,
}
return items, cursor, err
}
Assuming there are 4 items in the collection that have the name "test item n", we can then get the first page of results sorted by name by calling the items store's find method:
searchQuery := bson.M{"name": bson.RegEx{Pattern: "test item.*", Options: "i"}}
englishCollation := mgo.Collation{Locale: "en", Strength: 3}
// Arguments: query, next, previous, limit, sortAsc, paginatedField, collation
foundItems, cursor, err := store.Find(searchQuery, "", "", 2, true, "name", englishCollation)
To get the next page:
// Arguments: query, next, previous, limit, sortAsc, paginatedField, collation
foundItems, cursor, err = store.Find(searchQuery, cursor.Next, "", 2, true, "name", englishCollation)
from the second page, we can get to first page:
// Arguments: query, next, previous, limit, sortAsc, paginatedField, collation
foundItems, cursor, err = store.Find(searchQuery, "", cursor.Previous, 2, true, "name", englishCollation)
See items_store_test.go for the integration test that uses the items store's find method.
TODO