Skip to content

MetaDiv-AI/metamongo

Repository files navigation

metamongo

A generic MongoDB repository library for Go that provides a type-safe, fluent API for CRUD operations, query building, pagination, and aggregation. Built on top of the official MongoDB Go Driver.

Installation

go get github.com/MetaDiv-AI/metamongo

Requirements

  • Go 1.23+
  • MongoDB 4.0+

Features

  • Generic repository pattern — Type-safe repositories for any model
  • Fluent query builder — Chainable API for building MongoDB queries
  • CRUD operations — Save, SaveAll, Delete, DeleteAll, QueriedDelete
  • Rich query operators — Eq, Neq, Gt, Lt, In, Like, Regex, geospatial, and more
  • Pagination & sorting — Built-in support for paginated queries
  • Aggregation — Pipeline builder and direct aggregation support
  • Index management — IndexBuilder for creating text, compound, unique, TTL, and geospatial indexes
  • Connection helper — MongoConnector for easy connection setup (local and Atlas)

Quick Start

1. Define Your Model

Models must have an ID field of type primitive.ObjectID or string, and optionally implement IModel for collection name:

import (
    "go.mongodb.org/mongo-driver/bson/primitive"
)

type User struct {
    ID    primitive.ObjectID `bson:"_id,omitempty" json:"id"`
    Name  string             `bson:"name" json:"name"`
    Email string             `bson:"email" json:"email"`
}

func (u *User) CollectionName() string {
    return "users"
}

2. Connect to MongoDB

import (
    "github.com/MetaDiv-AI/metamongo"
)

// Using the connector (Atlas or local)
connector := metamongo.NewConnector()
client, err := connector.
    URI("cluster0.xxxxx.mongodb.net").  // or "localhost:27017" for local
    Username("user").
    Password("password").
    Database("mydb").
    Connect()
if err != nil {
    log.Fatal(err)
}
defer client.Disconnect(context.Background())

// Or with an existing mongo.Client
db := metamongo.NewDatabase(client, "mydb")

3. Create a Repository and Use It

// Create repository
repo := metamongo.NewRepository[User](db, "users")

// Save (upsert)
user := &User{Name: "Alice", Email: "alice@example.com"}
afterSave := repo.Save(user)
savedUser, err := afterSave.Model()

// Find by ID
user, err := repo.FindByHex("507f1f77bcf86cd799439011")

// Find with query
qb := metamongo.NewQueryBuilder()
users, err := repo.
    Query(qb.Field("name").Eq("Alice")).
    Sorting(metamongo.Sort("name", true)).
    FindMany()

// Paginated find
users, pagination, err := repo.
    Query(qb.Field("email").Like("example")).
    Pagination(metamongo.Paginate(1, 10)).
    Sorting(metamongo.Sort("name", true)).
    PagedFindMany()

// Delete
err = repo.Delete(user)

Query Builder

Build complex queries with a fluent API:

qb := metamongo.NewQueryBuilder()

// Simple comparisons
qb.Field("age").Eq(25)
qb.Field("age").Gt(18).Lt(65)
qb.Field("status").In([]string{"active", "pending"})
qb.Field("name").Like("john")
qb.Field("email").Regex("^admin@", "i")

// Null checks
qb.Field("deletedAt").IsNull()
qb.Field("optional").Exists()

// Array operations
qb.Field("tags").Size(3)
qb.Field("tags").All([]string{"go", "mongodb"})
qb.Field("items").ElemMatch(bson.M{"status": "active"})

// Logical operators
qb.And(
    qb.Field("age").Gte(18),
    qb.Field("status").Eq("active"),
)
qb.Or(
    qb.Field("role").Eq("admin"),
    qb.Field("role").Eq("moderator"),
)

// Text search (requires text index)
qb.Text("search term")

// Geospatial
qb.Field("location").NearSphere(bson.M{
    "$geometry": bson.M{
        "type":        "Point",
        "coordinates": []float64{-73.9667, 40.78},
    },
})

Repository API

Executor (Write Operations)

Method Description
Save(model) Upsert a single document
SaveAll(models) Upsert multiple documents
Delete(model) Delete by document reference
DeleteAll(models) Delete multiple documents
QueriedDelete(query) Delete documents matching query

Querier (Read Operations)

Method Description
FindOne() Find single document
FindMany() Find multiple documents
FindById(id) Find by ObjectID
FindByHex(hex) Find by hex string ID
FindManyByIds(ids) Find by slice of hex IDs
Count() Count matching documents
PagedFindMany() Find with pagination metadata
Aggregate(pipeline) Run aggregation pipeline
Distinct(field) Get distinct values

Query Modifiers

Chain these before executing a query:

  • Query(query) — Set filter
  • Pagination(pagination) — Set page and size
  • Sorting(sorting) — Set sort field and direction
  • Projection(projection) — Set field projection
  • Skip(n) / Limit(n) — Set skip/limit

Index Builder

Create indexes on collections:

indexes := metamongo.NewIndexBuilder().
    AddTextIndex("name", "description").
    AddCompoundIndex(bson.D{{Key: "email", Value: 1}}).
    AddUniqueIndex(bson.D{{Key: "email", Value: 1}}).
    AddTTLIndex("expiresAt", 3600).
    AddGeospatialIndex("location", "2dsphere").
    Build()

err := metamongo.CreateIndexes(db, "users", indexes)

Aggregate Builder

Build aggregation pipelines fluently:

pipeline := metamongo.NewAggregateBuilder().
    Match(bson.M{"status": "active"}).
    Group(bson.M{
        "_id":   "$category",
        "count": bson.M{"$sum": 1},
    }).
    Sort(bson.M{"count": -1}).
    Limit(10).
    Build()

results, err := repo.Aggregate(pipeline)

Or execute directly:

results, err := metamongo.NewAggregateBuilder().
    Match(bson.M{"status": "active"}).
    Count("total").
    Execute(db, "users")

License

See the repository for license information.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages