SkillAgentSearch skills...

Mgm

Mongo Go Models (mgm) is a fast and simple MongoDB ODM for Go (based on official Mongo Go Driver)

Install / Use

/learn @Kamva/Mgm
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<p align="center"> <img width="250" src="https://user-images.githubusercontent.com/22454054/71487214-759cb680-282f-11ea-9bcf-caa663b3e348.png" /> </p> <p align="center"> <a href="https://goreportcard.com/report/github.com/Kamva/mgm"> <img src="https://goreportcard.com/badge/github.com/Kamva/mgm"> </a> <a href="https://godoc.org/github.com/Kamva/mgm"> <img src="https://godoc.org/github.com/Kamva/mgm?status.svg" alt="GoDoc"> </a> <a href="https://travis-ci.com/Kamva/mgm"> <img src="https://travis-ci.com/Kamva/mgm.svg?branch=master" alt="Build Status"> </a> <a href="https://codecov.io/gh/Kamva/mgm"> <img src="https://codecov.io/gh/Kamva/mgm/branch/master/graph/badge.svg" /> </a> </p>

Mongo Go Models

The Mongo ODM for Go

Features

  • Define your models and perform CRUD operations with hooks before/after each operation.
  • mgm makes Mongo search and aggregation super easy to do in Golang.
  • Just set up your configs once and get collections anywhere you need them.
  • mgm predefines all Mongo operators and keys, so you don't have to hardcode them yourself.
  • mgm wraps the official Mongo Go Driver.

Requirements

  • Go 1.17 or higher.
  • MongoDB 3.6 and higher.

Installation

go get github.com/kamva/mgm/v3

Usage

To get started, import the mgm package and setup the default config:

import (
   "github.com/kamva/mgm/v3"
   "go.mongodb.org/mongo-driver/mongo/options"
)

func init() {
   // Setup the mgm default config
   err := mgm.SetDefaultConfig(nil, "mgm_lab", options.Client().ApplyURI("mongodb://root:12345@localhost:27017"))
}

Define your model:

type Book struct {
   // DefaultModel adds _id, created_at and updated_at fields to the Model.
   mgm.DefaultModel `bson:",inline"`
   Name             string `json:"name" bson:"name"`
   Pages            int    `json:"pages" bson:"pages"`
}

func NewBook(name string, pages int) *Book {
   return &Book{
      Name:  name,
      Pages: pages,
   }
}

Insert new document:

book := NewBook("Pride and Prejudice", 345)

// Make sure to pass the model by reference (to update the model's "updated_at", "created_at" and "id" fields by mgm).
err := mgm.Coll(book).Create(book)

Find one document

// Get the document's collection
book := &Book{}
coll := mgm.Coll(book)

// Find and decode the doc to a book model.
_ = coll.FindByID("5e0518aa8f1a52b0b9410ee3", book)

// Get the first doc of the collection 
_ = coll.First(bson.M{}, book)

// Get the first doc of a collection using a filter
_ = coll.First(bson.M{"pages":400}, book)

Update a document

// Find your book
book := findMyFavoriteBook()

// and update it
book.Name = "Moulin Rouge!"
err := mgm.Coll(book).Update(book)

Delete a document

// Just find and delete your document
err := mgm.Coll(book).Delete(book)

Find and decode a result:

result := []Book{}

err := mgm.Coll(&Book{}).SimpleFind(&result, bson.M{"pages": bson.M{operator.Gt: 24}})

A Model's Default Fields

Each model by default (by using DefaultModel struct) has the following fields:

  • _id : The document ID.

  • created_at: The creation date of a doc. When saving a new doc, this is automatically populated by the Creating hook.

  • updated_at: The last updated date of a doc. When saving a doc, this is automatically populated by the Saving hook.

You can even implement your own default model to customize its fields.

A Model's Hooks

Each model has the following hooks:

  • Creating: Called when creating a new model. Signature : Creating(context.Context) error

  • Created: Called after a new model is created. Signature : Created(context.Context) error

  • Updating: Called when updating model. Signature : Updating(context.Context) error

  • Updated : Called after a model is updated. Signature : Updated(ctx context.Context, result *mongo.UpdateResult) error

  • Saving: Called when creating or updating a model. Signature : Saving(context.Context) error

  • Saved: Called after a model is created or updated. Signature: Saved(context.Context) error

  • Deleting: Called when deleting a model. Signature: Deleting(context.Context) error

  • Deleted: Called after a model is deleted. Signature: Deleted(ctx context.Context, result *mongo.DeleteResult) error

Notes about hooks:

  • Each model by default uses the Creating and Saving hooks, so if you want to define those hooks yourself, remember to invoke the DefaultModel hooks from your own hooks.
  • Collection methods that call these hooks:
    • Create & CreateWithCtx
    • Update & UpdateWithCtx
    • Delete & DeleteWithCtx

Example:

func (model *Book) Creating(ctx context.Context) error {
   // Call the DefaultModel Creating hook
   if err := model.DefaultModel.Creating(ctx); err!=nil {
      return err
   }

   // We can validate the fields of a model and return an error to prevent a document's insertion.
   if model.Pages < 1 {
      return errors.New("book must have at least one page")
   }

   return nil
}

Configuration

The mgm default configuration has a context timeout:

func init() {
   _ = mgm.SetDefaultConfig(&mgm.Config{CtxTimeout:12 * time.Second}, "mgm_lab", options.Client().ApplyURI("mongodb://root:12345@localhost:27017"))
}

// To get the context, just call the Ctx() method, assign it to a variable
ctx := mgm.Ctx()

// and use it
coll := mgm.Coll(&Book{})
coll.FindOne(ctx, bson.M{})

// Or invoke Ctx() and use it directly
coll.FindOne(mgm.Ctx(), bson.M{})

Collections

Get a model's collection:

coll := mgm.Coll(&Book{})

// Do something with the collection

mgm automatically detects the name of a model's collection:

book := Book{}

// Print your model's collection name.
collName := mgm.CollName(&book)
fmt.Println(collName) // output: books

You can also set a custom collection name for your model by implementing the CollectionNameGetter interface:

func (model *Book) CollectionName() string {
   return "my_books"
}

// mgm returns the "my_books" collection
coll := mgm.Coll(&Book{})

Get a collection by its name (without needing to define a model for it):

coll := mgm.CollectionByName("my_coll")
   
// Do Aggregation, etc. with the collection

Customize the model db by implementing the CollectionGetter interface:

func (model *Book) Collection() *mgm.Collection {
    // Get default connection client
   _, client, _, err := mgm.DefaultConfigs()

   if err != nil {
      panic(err)
   }

   db := client.Database("another_db")
   return mgm.NewCollection(db, "my_collection")
}

Or return a model's collection from another connection:

func (model *Book) Collection() *mgm.Collection {
   // Create new client
   client, err := mgm.NewClient(options.Client().ApplyURI("mongodb://root:12345@localhost:27017"))

   if err != nil {
      panic(err)
   }

   // Get the model's db
   db := client.Database("my_second_db")

   // return the model's custom collection
   return mgm.NewCollection(db, "my_collection")
}

Aggregation

While we can use Mongo Go Driver Aggregate features, mgm also provides simpler methods to perform aggregations:

Run an aggregation and decode the result:

authorCollName := mgm.Coll(&Author{}).Name()
result := []Book{}

// Lookup with just a single line of code
_ := mgm.Coll(&Book{}).SimpleAggregate(&result, builder.Lookup(authorCollName, "auth_id", "_id", "author"))

// Multi stage (mix of mgm builders and raw stages)
_ := mgm.Coll(&Book{}).SimpleAggregate(&result,
		builder.Lookup(authorCollName, "auth_id", "_id", "author"),
		M{operator.Project: M{"pages": 0}},
)

// Do something with result...

Do aggregations using the mongo Aggregation method:

import (
   "github.com/kamva/mgm/v3"
   "github.com/kamva/mgm/v3/builder"
   "github.com/kamva/mgm/v3/field"
   . "go.mongodb.org/mongo-driver/bson"
   "go.mongodb.org/mongo-driver/bson/primitive"
)

// The Author model collection
authorColl := mgm.Coll(&Author{})

cur, err := mgm.Coll(&Book{}).Aggregate(mgm.Ctx(), A{
    // The S function accepts operators as parameters and returns a bson.M type.
    builder.S(builder.Lookup(authorColl.Name(), "author_id", field.Id, "author")),
})

A more complex example and mixes with mongo raw pipelines:

import (
   "github.com/kamva/mgm/v3"
   "github.com/kamva/mgm/v3/builder"
   "github.com/kamva/mgm/v3/field"
   "github.com/kamva/mgm/v3/operator"
   . "go.mongodb.org/mongo-driver/bson"
   "go.mongodb.org/mongo-driver/bson/primitive"
)

// Author model collection
authorColl := mgm.Coll(&Author{})

_, err := mgm.Coll(&Book{}).Aggregate(mgm.Ctx(), A{
    // S function get operators and return bson.M type.
    builder.S(builder.Lookup(authorColl.Name(), "author_id", field.Id, "author")),
    builder.S(builder.Group("pages", M{"books": M{operator.Push: M{"name": "$name", "author": "$author"}}})),
    M{operator.Unwind: "$books"},
})

if err != nil {
    panic(err)
}

Transactions

  • To run a transaction on the default connection use the mgm.Transaction() function, e.g:
d := &Doc{Name: "Mehran", Age: 10}

err := mgm.Transaction(func(session mongo.Session, sc mongo.SessionContext) error {

   // do not forget to pass the session's context to the collection methods.
	err := mgm.Coll(d).CreateWithCtx(sc, d)

	if err != nil {
		return err
	}

	return session.CommitTransaction(sc)
})
  • To run a transaction with your own context, use the mgm.TransactionWithCtx() method.
  • To run a transaction on another connection, use the mgm.TransactionWithClient() method.

Other Mongo Go Models Packages

**We implemented these packages to simpli

View on GitHub
GitHub Stars763
CategoryDevelopment
Updated4d ago
Forks63

Languages

Go

Security Score

100/100

Audited on Mar 24, 2026

No findings