Skip to content

qlik-oss/mongocursorpagination

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CircleCI Test Coverage GoDoc

mongocursorpagination

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.

Examples

mgo

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.

mongo-go-driver

TODO