### Handle MongoDB Pagination Errors in Go Source: https://context7.com/qlik-oss/mongocursorpagination/llms.txt Illustrates how to handle specific error types returned by the mongocursorpagination library. It covers identifying and managing cursor parsing errors, missing paginated field errors, and invalid results errors. The example also shows how to validate FindParams before making a query. ```go package main import ( "context" "errors" "fmt" mongocursorpagination "github.com/qlik-oss/mongocursorpagination/mongo" "go.mongodb.org/mongo-driver/bson" ) type User struct { ID string `bson:"_id"` Name string `bson:"name"` } func handlePaginationErrors(ctx context.Context, col mongocursorpagination.Collection) { var users []User fp := mongocursorpagination.FindParams{ Collection: col, Query: bson.M{}, Limit: 10, PaginatedField: "email", // Field not in User struct! Next: "invalid-cursor-string", } _, err := mongocursorpagination.Find(ctx, fp, &users) if err != nil { // Check for cursor parsing errors var cursorErr *mongocursorpagination.CursorError if errors.As(err, &cursorErr) { fmt.Printf("Invalid cursor: %v\n", cursorErr) // Handle by starting from first page fp.Next = "" fp.Previous = "" } // Check for missing paginated field error // ErrPaginatedFieldNotFound is returned when the struct lacks // a bson tag matching the PaginatedField if err.Error() == "paginated field email not found" { fmt.Println("Paginated field must match a bson tag in result struct") } // Check for invalid results error // ErrInvalidResults when results is nil, not a pointer, or not a slice if err.Error() == "expected results to be a slice pointer" { fmt.Println("Pass a pointer to a slice as results parameter") } } // Validation errors for FindParams fp2 := mongocursorpagination.FindParams{ Collection: nil, // Will cause error Limit: 0, // Will cause error: "a limit of at least 1 is required" } _, err = mongocursorpagination.Find(ctx, fp2, &users) if err != nil { fmt.Printf("Params validation error: %v\n", err) } } ``` -------------------------------- ### Create Item Store with Pagination (Go) Source: https://context7.com/qlik-oss/mongocursorpagination/llms.txt Demonstrates creating an ItemStore that utilizes the mongocursorpagination library to handle paginated retrieval of items from a MongoDB collection. It defines item structures, a collection wrapper, and repository methods for finding items by category and price range. ```go package main import ( "context" "time" mongocursorpagination "github.com/qlik-oss/mongocursorpagination/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) type Item struct { ID primitive.ObjectID `bson:"_id"` Name string `bson:"name"` Category string `bson:"category"` Price float64 `bson:"price"` CreatedAt time.Time `bson:"createdAt"` } type PaginatedResult struct { Items []*Item NextCursor string PrevCursor string HasNext bool HasPrev bool Total int } type ItemStore struct { col *CollectionWrapper } type CollectionWrapper struct { collection *mongo.Collection } func (c *CollectionWrapper) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) (mongocursorpagination.MongoCursor, error) { return c.collection.Find(ctx, filter, opts...) } func (c *CollectionWrapper) CountDocuments(ctx context.Context, filter interface{}, opts ...*options.CountOptions) (int64, error) { return c.collection.CountDocuments(ctx, filter, opts...) } func NewItemStore(collection *mongo.Collection) *ItemStore { return &ItemStore{col: &CollectionWrapper{collection: collection}} } func (s *ItemStore) FindByCategory(ctx context.Context, category string, nextCursor, prevCursor string, limit int64) (*PaginatedResult, error) { var items []*Item fp := mongocursorpagination.FindParams{ Collection: s.col, Query: bson.M{"category": category}, Limit: limit, SortAscending: true, PaginatedField: "name", Collation: &options.Collation{Locale: "en", Strength: 2}, Next: nextCursor, Previous: prevCursor, CountTotal: true, Timeout: 30 * time.Second, } cursor, err := mongocursorpagination.Find(ctx, fp, &items) if err != nil { return nil, err } return &PaginatedResult{ Items: items, NextCursor: cursor.Next, PrevCursor: cursor.Previous, HasNext: cursor.HasNext, HasPrev: cursor.HasPrevious, Total: cursor.Count, }, nil } func (s *ItemStore) FindByPriceRange(ctx context.Context, minPrice, maxPrice float64, nextCursor string, limit int64) (*PaginatedResult, error) { var items []*Item fp := mongocursorpagination.FindParams{ Collection: s.col, Query: bson.M{ "price": bson.M{" $gte": minPrice, "$lte": maxPrice}, }, Limit: limit, PaginatedFields: []string{"price", "name"}, SortOrders: []int{1, 1}, Next: nextCursor, CountTotal: true, } cursor, err := mongocursorpagination.Find(ctx, fp, &items) if err != nil { return nil, err } return &PaginatedResult{ Items: items, NextCursor: cursor.Next, PrevCursor: cursor.Previous, HasNext: cursor.HasNext, HasPrev: cursor.HasPrevious, Total: cursor.Count, }, nil } ``` -------------------------------- ### Fetch Raw BSON Documents with MongoDB Pagination Source: https://context7.com/qlik-oss/mongocursorpagination/llms.txt Demonstrates how to retrieve raw BSON documents from MongoDB using the mongocursorpagination library. This approach is useful for flexible schema handling or when avoiding struct unmarshaling overhead. It shows how to process these raw documents and how pagination functions similarly to when using structured results. ```go package main import ( "context" "fmt" mongocursorpagination "github.com/qlik-oss/mongocursorpagination/mongo" "go.mongodb.org/mongo-driver/bson" ) func findRawDocuments(ctx context.Context, col mongocursorpagination.Collection) { // Use []bson.Raw for flexible document handling var rawResults []bson.Raw fp := mongocursorpagination.FindParams{ Collection: col, Query: bson.M{}, Limit: 10, PaginatedField: "_id", // Default if not specified CountTotal: true, } cursor, err := mongocursorpagination.Find(ctx, fp, &rawResults) if err != nil { panic(err) } fmt.Printf("Found %d documents (total: %d)\n", len(rawResults), cursor.Count) // Process raw BSON documents for _, raw := range rawResults { // Decode specific fields as needed var doc struct { ID interface{} `bson:"_id"` Name string `bson:"name"` } if err := bson.Unmarshal(raw, &doc); err == nil { fmt.Printf("Document: %v - %s\n", doc.ID, doc.Name) } // Or access raw bytes for custom processing // elements, _ := raw.Elements() } // Pagination works the same with raw results if cursor.HasNext { fp.Next = cursor.Next var nextRaw []bson.Raw mongocursorpagination.Find(ctx, fp, &nextRaw) } } ``` -------------------------------- ### Calling mgo Find for First Page Source: https://github.com/qlik-oss/mongocursorpagination/blob/master/README.md Demonstrates how to call the `Find` method to retrieve the first page of paginated results. It sets up the search query, collation, and pagination parameters, including an empty `next` and `previous` cursor for the initial request. ```go 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) ``` -------------------------------- ### Configure FindParams for Paginated MongoDB Queries (Go) Source: https://context7.com/qlik-oss/mongocursorpagination/llms.txt Demonstrates how to configure the `FindParams` struct in Go for paginated MongoDB queries. This includes setting the collection, query filter, limit, sort order, paginated field, and optional parameters like collation, cursors, total count, hint, projection, and timeout. ```go package main import ( "time" mongocursorpagination "github.com/qlik-oss/mongocursorpagination/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" ) func configureFindParams(col mongocursorpagination.Collection) mongocursorpagination.FindParams { return mongocursorpagination.FindParams{ // Required: Collection implementing the Collection interface Collection: col, // Query filter - standard MongoDB query document Query: bson.M{ "status": "active", "createdAt": bson.M{"$": "$gte", "value": time.Now().AddDate(0, -1, 0)}, }, // Number of results per page (must be > 0) Limit: 25, // Sort direction for the paginated field SortAscending: true, // Field to paginate on - must be indexed and immutable // Automatically includes _id as secondary sort for uniqueness PaginatedField: "createdAt", // Optional: Collation for locale-aware string sorting Collation: &options.Collation{ Locale: "en", Strength: 2, // Case-insensitive }, // Cursor strings from previous query results Next: "", // Pass cursor.Next for next page Previous: "", // Pass cursor.Previous for previous page // Optional: Include total count (adds extra query) CountTotal: true, // Optional: Index hint for query optimization Hint: "createdAt_1__id_1", // Optional: Field projection to limit returned fields Projection: bson.D{ {Key: "_id", Value: 1}, {Key: "name", Value: 1}, {Key: "createdAt", Value: 1}, }, // Optional: Query timeout (defaults to 45 seconds) Timeout: 60 * time.Second, } } ``` -------------------------------- ### Configure mgo Driver Pagination Parameters Source: https://context7.com/qlik-oss/mongocursorpagination/llms.txt Defines and configures the `FindParams` struct for paginating MongoDB results using the mgo driver. This includes setting the database, collection, query filters, sorting, pagination fields, and navigation cursors. ```go package main import ( "github.com/globalsign/mgo" "github.com/globalsign/mgo/bson" mongocursorpagination "github.com/qlik-oss/mongocursorpagination/mgo" ) func configureMgoFindParams(db *mgo.Database) mongocursorpagination.FindParams { return mongocursorpagination.FindParams{ // Database connection (implements MgoDb interface) DB: db, // Collection name as string CollectionName: "users", // Query filter using mgo/bson types Query: bson.M{ "active": true, "role": bson.M{"$in": []string{"admin", "editor"}}, }, // Results per page Limit: 50, // Sort direction SortAscending: false, // Descending order // Field to paginate on (must have bson tag in result struct) PaginatedField: "createdAt", // Collation for string sorting Collation: &mgo.Collation{ Locale: "en", Strength: 3, }, // Navigation cursors Next: "", // Empty for first page Previous: "", // Include total count CountTotal: true, // Multi-field pagination (optional, overrides PaginatedField) PaginatedFields: []string{"lastName", "firstName"}, SortOrders: []int{1, 1}, // Both ascending } } ``` -------------------------------- ### Calling mgo Find for Next Page Source: https://github.com/qlik-oss/mongocursorpagination/blob/master/README.md Shows how to fetch the subsequent page of results using the `cursor.Next` value obtained from a previous query. This allows for sequential navigation through the paginated data. ```go // Arguments: query, next, previous, limit, sortAsc, paginatedField, collation foundItems, cursor, err = store.Find(searchQuery, cursor.Next, "", 2, true, "name", englishCollation) ``` -------------------------------- ### Paginate MongoDB Results with mgo Driver Source: https://context7.com/qlik-oss/mongocursorpagination/llms.txt Performs a paginated query on a MongoDB collection using the legacy mgo driver. It fetches a page of articles, prints the total count and the number of articles on the current page, and demonstrates how to retrieve the next and previous pages. ```go package main import ( "fmt" "time" "github.com/globalsign/mgo" "github.com/globalsign/mgo/bson" mongocursorpagination "github.com/qlik-oss/mongocursorpagination/mgo" ) type Article struct { ID bson.ObjectId `bson:"_id"` Title string `bson:"title"` Author string `bson:"author"` CreatedAt time.Time `bson:"createdAt"` } func main() { session, err := mgo.Dial("mongodb://localhost:27017") if err != nil { panic(err) } defer session.Close() db := session.DB("blog") // First page - ascending by title with English collation var articles []*Article fp := mongocursorpagination.FindParams{ DB: db, CollectionName: "articles", Query: bson.M{"author": "John Doe"}, Limit: 10, SortAscending: true, PaginatedField: "title", Collation: &mgo.Collation{ Locale: "en", Strength: 2, // Case-insensitive comparison }, CountTotal: true, } cursor, err := mongocursorpagination.Find(fp, &articles) if err != nil { panic(err) } fmt.Printf("Total articles: %d\n", cursor.Count) fmt.Printf("Page 1: %d articles\n", len(articles)) for _, a := range articles { fmt.Printf(" - %s\n", a.Title) } // Get next page if cursor.HasNext { fp.Next = cursor.Next fp.Previous = "" var nextArticles []*Article cursor, _ = mongocursorpagination.Find(fp, &nextArticles) fmt.Printf("\nPage 2: %d articles\n", len(nextArticles)) } // Navigate to previous page if cursor.HasPrevious { fp.Next = "" fp.Previous = cursor.Previous var prevArticles []*Article cursor, _ = mongocursorpagination.Find(fp, &prevArticles) fmt.Printf("\nBack to previous: %d articles\n", len(prevArticles)) } } ``` -------------------------------- ### mgo Find Function for Paginated Results Source: https://github.com/qlik-oss/mongocursorpagination/blob/master/README.md Implements cursor-based pagination for the mgo driver. It takes query parameters, collection, and pagination details to return a subset of items and cursor information for navigating between pages. Dependencies include the mgo driver and the mongocursorpagination package. ```go 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 } ``` -------------------------------- ### Paginated Query with Official MongoDB Driver (Go) Source: https://context7.com/qlik-oss/mongocursorpagination/llms.txt Executes paginated queries using the official MongoDB Go driver. It takes FindParams for configuration, applies cursor-based pagination logic, and returns results along with navigation cursor information. Requires the official MongoDB Go driver. ```go package main import ( "context" "fmt" "time" mongocursorpagination "github.com/qlik-oss/mongocursorpagination/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) type Product struct { ID primitive.ObjectID `bson:"_id"` Name string `bson:"name"` Price float64 `bson:"price"` CreatedAt time.Time `bson:"createdAt"` } // CollectionWrapper implements mongocursorpagination.Collection interface type CollectionWrapper struct { collection *mongo.Collection } func (c *CollectionWrapper) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) (mongocursorpagination.MongoCursor, error) { return c.collection.Find(ctx, filter, opts...) } func (c *CollectionWrapper) CountDocuments(ctx context.Context, filter interface{}, opts ...*options.CountOptions) (int64, error) { return c.collection.CountDocuments(ctx, filter, opts...) } func main() { ctx := context.Background() client, _ := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017")) col := &CollectionWrapper{collection: client.Database("shop").Collection("products")} // First page - no cursor needed var products []Product fp := mongocursorpagination.FindParams{ Collection: col, Query: bson.M{"price": bson.M{"$": 10.0}}, Limit: 10, SortAscending: true, PaginatedField: "name", Collation: &options.Collation{Locale: "en", Strength: 3}, CountTotal: true, Timeout: 30 * time.Second, } cursor, err := mongocursorpagination.Find(ctx, fp, &products) if err != nil { panic(err) } fmt.Printf("Found %d total products, showing %d\n", cursor.Count, len(products)) fmt.Printf("Has next: %v, Next cursor: %s\n", cursor.HasNext, cursor.Next) // Next page - use the cursor from previous result fp.Next = cursor.Next fp.Previous = "" var nextPageProducts []Product cursor, _ = mongocursorpagination.Find(ctx, fp, &nextPageProducts) fmt.Printf("Page 2: %d products, Has previous: %v\n", len(nextPageProducts), cursor.HasPrevious) // Previous page - navigate back fp.Next = "" fp.Previous = cursor.Previous var prevPageProducts []Product cursor, _ = mongocursorpagination.Find(ctx, fp, &prevPageProducts) fmt.Printf("Back to page 1: %d products\n", len(prevPageProducts)) } ``` -------------------------------- ### Multi-Field Pagination for Complex Sorting in MongoDB (Go) Source: https://context7.com/qlik-oss/mongocursorpagination/llms.txt Illustrates how to perform pagination on multiple fields in MongoDB using Go. This approach is useful for handling duplicate values in the primary sort field by specifying `PaginatedFields` and corresponding `SortOrders`. ```go package main import ( "context" "fmt" mongocursorpagination "github.com/qlik-oss/mongocursorpagination/mongo" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type Order struct { ID primitive.ObjectID `bson:"_id"` CustomerID string `bson:"customerId"` Amount float64 `bson:"amount"` Status string `bson:"status"` } func findOrdersMultiField(ctx context.Context, col mongocursorpagination.Collection, nextCursor string) ([]Order, mongocursorpagination.Cursor, error) { var orders []Order fp := mongocursorpagination.FindParams{ Collection: col, Query: bson.M{"status": "completed"}, Limit: 20, // Multiple fields for pagination - takes precedence over PaginatedField // _id is automatically appended if not included PaginatedFields: []string{"amount", "customerId"}, // Corresponding sort orders: 1 = ascending, -1 = descending // Must match length of PaginatedFields SortOrders: []int{-1, 1}, // Sort by amount DESC, then customerId ASC Next: nextCursor, CountTotal: true, } cursor, err := mongocursorpagination.Find(ctx, fp, &orders) if err != nil { return nil, mongocursorpagination.Cursor{}, fmt.Errorf("find failed: %w", err) } return orders, cursor, nil } func main() { // Example usage showing multi-field pagination ctx := context.Background() // col := ... // Initialize your collection wrapper // First page // orders, cursor, _ := findOrdersMultiField(ctx, col, "") // fmt.Printf("Orders sorted by amount DESC, customerId ASC: %d results\n", len(orders)) // Next page using the cursor // nextOrders, nextCursor, _ := findOrdersMultiField(ctx, col, cursor.Next) // fmt.Printf("Next page: %d results, has more: %v\n", len(nextOrders), nextCursor.HasNext) } ``` -------------------------------- ### Build Paginated API Response Structure with Go Source: https://context7.com/qlik-oss/mongocursorpagination/llms.txt Defines the APIResponse struct to wrap paginated data and cursor information. The buildResponse function populates this struct using data and a Cursor object from the pagination library. It handles setting next/previous cursors, pagination state, and total count. ```go package main import ( "encoding/json" "net/http" mongocursorpagination "github.com/qlik-oss/mongocursorpagination/mongo" ) // APIResponse wraps paginated results with cursor information type APIResponse struct { Data interface{} `json:"data"` Pagination struct { NextCursor string `json:"nextCursor,omitempty"` PreviousCursor string `json:"previousCursor,omitempty"` HasNext bool `json:"hasNext"` HasPrevious bool `json:"hasPrevious"` TotalCount int `json:"totalCount,omitempty"` } `json:"pagination"` } func buildResponse(items interface{}, cursor mongocursorpagination.Cursor) APIResponse { response := APIResponse{Data: items} // Cursor struct fields: // - Previous: URL-safe string for previous page (empty if no previous) // - Next: URL-safe string for next page (empty if no next) // - HasPrevious: true if previous page exists // - HasNext: true if next page exists // - Count: total document count (only if CountTotal was true) response.Pagination.NextCursor = cursor.Next response.Pagination.PreviousCursor = cursor.Previous response.Pagination.HasNext = cursor.HasNext response.Pagination.HasPrevious = cursor.HasPrevious response.Pagination.TotalCount = cursor.Count return response } func handleListItems(w http.ResponseWriter, r *http.Request) { // Extract cursors from query parameters nextCursor := r.URL.Query().Get("next") prevCursor := r.URL.Query().Get("previous") // Execute paginated query (implementation details omitted) // items, cursor, err := store.Find(ctx, query, nextCursor, prevCursor, 10, true, "name", nil, nil, nil) // Example cursor values for demonstration cursor := mongocursorpagination.Cursor{ Previous: "eyJfaWQiOiI1ZjE...", // Base64 encoded BSON Next: "eyJfaWQiOiI1ZjI...", HasPrevious: true, HasNext: true, Count: 150, } response := buildResponse([]string{"item1", "item2"}, cursor) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(response) } ``` -------------------------------- ### Calling mgo Find for Previous Page Source: https://github.com/qlik-oss/mongocursorpagination/blob/master/README.md Illustrates how to retrieve the previous page of results by passing the `cursor.Previous` value to the `Find` method. This enables backward navigation within the paginated dataset. ```go // Arguments: query, next, previous, limit, sortAsc, paginatedField, collation foundItems, cursor, err = store.Find(searchQuery, "", cursor.Previous, 2, true, "name", englishCollation) ``` -------------------------------- ### Generate MongoDB Queries Without Execution using Go Source: https://context7.com/qlik-oss/mongocursorpagination/llms.txt Demonstrates how to use the BuildQueries function to generate MongoDB query filters and sort specifications without executing them against the database. This is useful for debugging, logging, or constructing complex query pipelines. It takes FindParams as input and returns the query components and an error. ```go package main import ( "context" "encoding/json" "fmt" mongocursorpagination "github.com/qlik-oss/mongocursorpagination/mongo" "go.mongodb.org/mongo-driver/bson" ) func inspectGeneratedQueries(ctx context.Context, col mongocursorpagination.Collection) { fp := mongocursorpagination.FindParams{ Collection: col, Query: bson.M{"category": "electronics"}, Limit: 10, SortAscending: true, PaginatedField: "price", Next: "eyJwcmljZSI6OTkuOTksIl9pZCI6IjVmMWIuLi4ifQ", // Example cursor } // BuildQueries returns the query components without executing queries, sort, err := mongocursorpagination.BuildQueries(ctx, fp) if err != nil { fmt.Printf("Error building queries: %v\n", err) return } // queries is []bson.M containing: // - Original query filter // - Cursor-based range query (if Next or Previous provided) fmt.Println("Generated queries:") for i, q := range queries { jsonBytes, _ := json.MarshalIndent(q, "", " ") fmt.Printf("Query %d: %s\n", i, string(jsonBytes)) } // sort is bson.D with field/direction pairs fmt.Printf("\nSort specification: %v\n", sort) // Output: Sort specification: [{price 1} {_id 1}] // The final MongoDB query combines these with $and: // db.collection.find({$and: queries}).sort(sort).limit(11) } ``` -------------------------------- ### mgo Index Definition for Pagination Source: https://github.com/qlik-oss/mongocursorpagination/blob/master/README.md Defines a MongoDB index for efficient querying and pagination, particularly when sorting by a field other than '_id'. It includes the primary sort field and '_id' to ensure consistent ordering and support secondary sorting. The index supports case-insensitive sorting with a specified locale. ```go 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, } ``` -------------------------------- ### mgo Item Struct Definition Source: https://github.com/qlik-oss/mongocursorpagination/blob/master/README.md Defines the structure of an item stored in MongoDB, including its unique identifier, name, and creation timestamp. The `bson` tags are used to map struct fields to MongoDB document fields. ```go Item struct { ID bson.ObjectId `bson:"_id"` Name string `bson:"name"` CreatedAt time.Time `bson:"createdAt"` } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.