package mongo import ( "context" "go.mongodb.org/mongo-driver/v2/bson" "git.gsuntres.com/general/commons" ) type FindOptions struct { Offset int64 `json:"offset"` Limit int64 `json:"limit"` Alias string `json:"alias"` } // Find is used to fetch the first page of data. func (c *MongoClient) Find(ctx context.Context, database, name string, filter bson.M, opts *FindOptions) (bson.M, error) { var limit int64 if opts != nil { limit = opts.Limit } // 1. Prepare to query. finalName := name if opts != nil && commons.StringIsNotBlank(opts.Alias) { finalName = opts.Alias } collection := c.GetCollection(database, finalName) pageSize := max(limit, c.Limit) sort := bson.M{"_id": 1} if err := c.DiscriminatorCheckAndApplyToFilter(ctx, name, filter); err != nil { return nil, err } pipeline := BuildPaginationPipeline(0, pageSize + 1, filter, sort) // 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.D) totalValue, _ = commons.BsonDGetAny(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)) > pageSize { hasMore = true data = data[:pageSize] } out := bson.M{ "data": data, "has_more": hasMore, "total": total, } if hasMore { // next cursor var last bson.M = data[len(data) - 1].(bson.M) var nextCursor string lastId := last["_id"] nextCursor = EncodeCursor(lastId.(bson.ObjectID)) out["next_cursor"] = nextCursor } return out, nil } func (c *MongoClient) FindOffset(ctx context.Context, database, name string, filter bson.M, opts *FindOptions) (bson.M, error) { var offset int64 var limit int64 if opts != nil { limit = opts.Limit } // 1. Prepare to query. finalName := name if opts != nil && commons.StringIsNotBlank(opts.Alias) { finalName = opts.Alias } collection := c.GetCollection(database, finalName) finalLimit := max(limit, c.Limit) if err := c.DiscriminatorCheckAndApplyToFilter(ctx, name, filter); err != nil { return nil, err } f := Mongofy(&Query{ Filter: filter, }) pipeline := BuildPaginationPipeline(offset, finalLimit, f, 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.D) totalValue, _ = commons.BsonDGetAny(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 }