pagination optimization
This commit is contained in:
@@ -40,6 +40,14 @@ func collectionName() string {
|
||||
return "tenders"
|
||||
}
|
||||
|
||||
// tenderSearchListProjection excludes large fields not needed for list/search API payloads.
|
||||
func tenderSearchListProjection() bson.M {
|
||||
return bson.M{
|
||||
"content_xml": 0,
|
||||
"document_summaries": 0,
|
||||
}
|
||||
}
|
||||
|
||||
// tenderRepository implements TenderRepository interface using MongoDB ORM
|
||||
type tenderRepository struct {
|
||||
ormRepo orm.Repository[Tender]
|
||||
@@ -332,6 +340,7 @@ func (r *tenderRepository) Search(ctx context.Context, form *SearchForm, paginat
|
||||
Limit(pagination.Limit).
|
||||
Skip(pagination.Offset).
|
||||
SortBy(sort, sortOrder).
|
||||
Projection(tenderSearchListProjection()).
|
||||
Build()
|
||||
|
||||
result, err := r.ormRepo.FindAll(ctx, filter, paginationBuilder)
|
||||
|
||||
+12
-5
@@ -26,6 +26,8 @@ type Pagination struct {
|
||||
Cursor string `json:"cursor"` // Base64 encoded cursor for cursor-based pagination
|
||||
SortField string `json:"sortField"` // Field to sort by (default: "_id")
|
||||
SortOrder int `json:"sortOrder"` // Sort order: 1 for ascending, -1 for descending
|
||||
// Projection limits fields returned from Find (e.g. exclude large blobs on list endpoints).
|
||||
Projection bson.M `json:"projection,omitempty"`
|
||||
}
|
||||
|
||||
// PaginatedResult represents a paginated result set
|
||||
@@ -138,6 +140,10 @@ func (r *repository[T]) FindAll(ctx context.Context, filter bson.M, pagination P
|
||||
SetSort(sort).
|
||||
SetLimit(int64(pagination.Limit + 1)) // +1 to check if there are more documents
|
||||
|
||||
if len(pagination.Projection) > 0 {
|
||||
findOptions.SetProjection(pagination.Projection)
|
||||
}
|
||||
|
||||
// Handle cursor-based pagination
|
||||
if pagination.Cursor != "" {
|
||||
cursorFilter, err := r.buildCursorFilter(pagination.Cursor, pagination.SortField, pagination.SortOrder)
|
||||
@@ -181,13 +187,14 @@ func (r *repository[T]) FindAll(ctx context.Context, filter bson.M, pagination P
|
||||
items = items[:pagination.Limit] // Remove the extra item
|
||||
}
|
||||
|
||||
// Get total count
|
||||
totalCount, err := r.Count(ctx, filter)
|
||||
if err != nil {
|
||||
// Get total count for pagination metadata
|
||||
var totalCount int64
|
||||
var countErr error
|
||||
totalCount, countErr = r.Count(ctx, filter)
|
||||
if countErr != nil {
|
||||
r.logger.Error("Failed to get total count", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"error": countErr.Error(),
|
||||
})
|
||||
// Don't fail the entire query, just set count to 0
|
||||
totalCount = 0
|
||||
}
|
||||
|
||||
|
||||
+8
-3
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
// Index represents a MongoDB index
|
||||
type Index struct {
|
||||
Name string `json:"name"`
|
||||
Keys bson.D `json:"keys"`
|
||||
Name string `json:"name"`
|
||||
Keys bson.D `json:"keys"`
|
||||
Options *options.IndexOptionsBuilder `json:"options"`
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ func (i *Index) WithSparse(sparse bool) *Index {
|
||||
return i
|
||||
}
|
||||
|
||||
|
||||
// WithExpireAfterSeconds sets the TTL for the index
|
||||
func (i *Index) WithExpireAfterSeconds(seconds int32) *Index {
|
||||
i.Options.SetExpireAfterSeconds(seconds)
|
||||
@@ -294,6 +293,12 @@ func (pb *PaginationBuilder) SortDesc(field string) *PaginationBuilder {
|
||||
return pb.SortBy(field, "desc")
|
||||
}
|
||||
|
||||
// Projection sets optional MongoDB field projection for Find (e.g. exclude large fields).
|
||||
func (pb *PaginationBuilder) Projection(projection bson.M) *PaginationBuilder {
|
||||
pb.pagination.Projection = projection
|
||||
return pb
|
||||
}
|
||||
|
||||
// Build returns the final pagination options
|
||||
func (pb *PaginationBuilder) Build() Pagination {
|
||||
return pb.pagination
|
||||
|
||||
Reference in New Issue
Block a user