Add Find with offset

This commit is contained in:
George Suntres
2026-04-10 21:39:50 -04:00
parent 7a48d336e7
commit cca6601bea
2 changed files with 67 additions and 4 deletions

59
find.go
View File

@@ -104,6 +104,65 @@ func (c *MongoClient) Find(ctx context.Context, database, name string, filter bs
return out, nil return out, nil
} }
func (c *MongoClient) FindOffset(ctx context.Context, database, name string, filter bson.M, offset, limit int64) (bson.M, error) {
// 1. Prepare to query.
collection := c.GetCollection(database, name)
finalLimit := max(limit, c.Limit)
pipeline := BuildPaginationPipeline(offset, finalLimit, filter, nil)
// 2. Query
cursor, err := collection.Aggregate(ctx, pipeline)
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
// 3. Build results
var facetResults []bson.M
if err = cursor.All(ctx, &facetResults); err != nil {
return nil, err
}
root := facetResults[0]
data := root["data"].(bson.A)
metadata := root["metadata"].(bson.A)
var totalValue any
if len(metadata) != 0 {
metadataRoot := metadata[0].(bson.M)
totalValue = metadataRoot["total"]
}
var total int64
switch v := totalValue.(type) {
case int32:
total = int64(v)
case int64:
total = v
default:
total = 0
}
hasMore := false
if int64(len(data)) > finalLimit {
hasMore = true
data = data[:finalLimit]
}
out := bson.M{
"data": data,
"offset": offset,
"limit": finalLimit,
"has_more": hasMore,
"total": total,
}
return out, nil
}
// func (c *MongoClient) FindNext(ctx context.Context, database, name string, filter bson.M, nextCursor string, limit int64) ([]bson.M, error) { // func (c *MongoClient) FindNext(ctx context.Context, database, name string, filter bson.M, nextCursor string, limit int64) ([]bson.M, error) {
// collection := c.GetCollection(database, name) // collection := c.GetCollection(database, name)

View File

@@ -6,13 +6,10 @@ import (
) )
func BuildPaginationPipeline(skip, limit int64, filter bson.M, sort bson.M) mongo.Pipeline { func BuildPaginationPipeline(skip, limit int64, filter bson.M, sort bson.M) mongo.Pipeline {
return mongo.Pipeline{ pipe := mongo.Pipeline{
// 1. GLOBAL FILTER: Always filter first to use indexes // 1. GLOBAL FILTER: Always filter first to use indexes
{{Key: "$match", Value: filter}}, {{Key: "$match", Value: filter}},
// 2. GLOBAL SORT: Sort here so both 'total' and 'data' facets use the same order
{{Key: "$sort", Value: sort}},
// 3. FACET: Split the pipeline into two parallel paths // 3. FACET: Split the pipeline into two parallel paths
{{Key: "$facet", Value: bson.D{ {{Key: "$facet", Value: bson.D{
// Path A: Get the total count of documents matching the filter // Path A: Get the total count of documents matching the filter
@@ -26,6 +23,13 @@ func BuildPaginationPipeline(skip, limit int64, filter bson.M, sort bson.M) mong
}}, }},
}}}, }}},
} }
// 2. GLOBAL SORT: Sort here so both 'total' and 'data' facets use the same order
if sort != nil {
pipe = append(pipe, bson.D{{Key: "$sort", Value: sort}})
}
return pipe
} }
func BuildPaginationPipelineNext(limit int64, filter bson.M, sort bson.M) mongo.Pipeline { func BuildPaginationPipelineNext(limit int64, filter bson.M, sort bson.M) mongo.Pipeline {