Files
mongo/find.go
2026-04-20 13:08:13 -04:00

193 lines
3.7 KiB
Go

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 {
switch metadata[0].(type) {
case bson.D:
metadataRoot := metadata[0].(bson.D)
totalValue, _ = commons.BsonDGetAny(metadataRoot, "total")
case bson.M:
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)) > 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 {
switch metadata[0].(type) {
case bson.D:
metadataRoot := metadata[0].(bson.D)
totalValue, _ = commons.BsonDGetAny(metadataRoot, "total")
case bson.M:
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
}