Categorygithub.com/nextlinktechnology/mgm/v3
modulepackage
3.0.2
Repository: https://github.com/nextlinktechnology/mgm.git
Documentation: pkg.go.dev

# README

GoDoc Build Status

Mongo Go Models

The Mongo ODM for Go

Features

  • Define your models and do 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 one time and get collections anywhere you need those.
  • mgm predefined all Mongo operators and keys, So you don't have to hardcode them.
  • The wrapper of the official Mongo Go Driver.

Requirements

  • Go 1.10 or higher.
  • MongoDB 2.6 and higher.

Install

go get github.com/Kamva/mgm/v2

Usage

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

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

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

Define your model:

type Book struct {
   // DefaultModel add _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 pass the model by reference.
err := mgm.Coll(book).Create(book)

Find one document

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

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

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

// Get first doc of collection with filter
_ = coll.First(bson.M{"page":400}, book)

Update document

// Find your book
book:=findMyFavoriteBook()

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

Delete document

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

Find and decode result:

result := []Book{}

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

Model's default fields

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

  • _id : Document Id.

  • created_at: Creation date of doc. On save new doc, autofill by Creating hook.

  • updated_at: Last update date of doc. On save doc, autofill by Saving hook

Model's hooks:

Each model has these hooks :

  • Creating: Call On creating a new model.
    Signature : Creating() error

  • Created: Call On new model created.
    Signature : Created() error

  • Updating: Call on updating model.
    Signature : Updating() error

  • Updated : Call on models updated.
    Signature : Updated(result *mongo.UpdateResult) error

  • Saving: Call on creating or updating the model.
    Signature : Saving() error

  • Saved: Call on models Created or updated.
    Signature: Saved() error

  • Deleting: Call on deleting model.
    Signature: Deleting() error

  • Deleted: Call on models deleted.
    Signature: Deleted(result *mongo.DeleteResult) error

Important Note: Each model by default is using Creating and Saving hooks, So if you want to define those hooks, call to DefaultModel hooks in your defined hooks.

Example:

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

   // We can check if model fields is not valid, return error to
   // cancel document insertion .
   if model.Pages < 1 {
      return errors.New("book must have at least one page")
   }

   return nil
}

config :

mgm default config contains context timeout:

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

// To get context , just call to Ctx() method.
ctx:=mgm.Ctx()

// Now we can get context by calling to `Ctx` method.
coll := mgm.Coll(&Book{})
coll.FindOne(ctx,bson.M{})

// Or call it without assign variable to it.
coll.FindOne(mgm.Ctx(),bson.M{})

Collection

Get model collection:

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

// Do something with the collection

mgm automatically detect model's collection name:

book:=Book{}

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

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

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

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

Get collection by its name (without need of defining model for it):

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

Customize model db by implementing 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 model 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 model db
   db := client.Database("my_second_db")

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

Aggregation

while we can haveing Mongo Go Driver Aggregate features, mgm also provide simpler methods to aggregate:

Run aggregate and decode result:

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


// Lookup in just single line
_ := 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 aggregate using mongo Aggregation method:

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

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

cur, 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")),
})

More complex and mix with mongo raw pipelines:

import (
   "github.com/Kamva/mgm/v2"
   "github.com/Kamva/mgm/v2/builder"
   "github.com/Kamva/mgm/v2/field"
   "github.com/Kamva/mgm/v2/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)
}

Transaction

  • To run a transaction on default connection use 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 context, use mgm.TransactionWithCtx() method.
  • To run a transaction on another connection, use mgm.TransactionWithClient() method.

Mongo Go Models other packages

We implemented these packages to simplify query and aggregate in mongo

builder: simplify mongo query and aggregation.

operator : contain mongo operators as predefined variable.
(e.g Eq = "$eq" , Gt = "$gt")

field : contain mongo fields using in aggregation and ... as predefined variable. (e.g LocalField = "localField", ForeignField = "foreignField")

example:

import (
  "github.com/Kamva/mgm/v2"
  f "github.com/Kamva/mgm/v2/field"
  o "github.com/Kamva/mgm/v2/operator"
  "go.mongodb.org/mongo-driver/bson"
)

// Instead of hard-coding mongo operators and fields 
_, _ = mgm.Coll(&Book{}).Aggregate(mgm.Ctx(), bson.A{
   bson.M{"$count": ""},
   bson.M{"$project": bson.M{"_id": 0}},
})

// Use predefined operators and pipeline fields.
_, _ = mgm.Coll(&Book{}).Aggregate(mgm.Ctx(), bson.A{
   bson.M{o.Count: ""},
   bson.M{o.Project: bson.M{f.Id: 0}},
})

Bugs / Feature request

New Features and bugs can be reported on Github issue tracker.

Communicate With Us

Contributing

  1. Fork the repository
  2. Clone your fork (git clone https://github.com/<your_username>/mgm && cd mgm)
  3. Create your feature branch (git checkout -b my-new-feature)
  4. Make changes and add them (git add .)
  5. Commit your changes (git commit -m 'Add some feature')
  6. Push to the branch (git push origin my-new-feature)
  7. Create new pull request

License

Mongo Go Models is released under the Apache License

# Packages

Package builder help us to write aggregate,filter,update maps simpler.
No description provided by the author
No description provided by the author
No description provided by the author

# Functions

Coll return model's collection.
CollectionByName return new collection from default config.
CollName check if you provided collection name in your model, return it's name, otherwise guess model collection's name.
Ctx function create new context with default timeout and return it.
DefaultConfigs return you'r default mongodb configs.
NewClient return new mongodb client.
NewCollection return new collection with passed database.
NewCtx function create and return new context with your specified timeout.
ResetDefaultConfig reset all of the default config.
SetDefaultConfig initial default client and Database .
Transaction run a transaction with default client..
TransactionWithClient run transaction with the given client.
TransactionWithCtx run transaction with the given context and default client.

# Variables

Version variable.

# Structs

Collection performs operations on models and given Mongodb collection.
Config struct contain extra config of mgm package.
DateFields struct contain `created_at` and `updated_at` fields that autofill on insert/update model.
DefaultModel struct contain model's default fields.
IDField struct contain model's ID field.

# Interfaces

CollectionGetter interface contain method to return model's custom collection.
CollectionNameGetter interface contain method to return collection name of model.
CreatedHook call after model has been created.
CreatingHook call before saving new model into database.
DeletedHook call after model has been deleted).
DeletingHook call before deleting model.
Model interface is base method that must implement by each model, If you're using `DefaultModel` struct in your model, don't need to implement any of those method.
SavedHook call after model has been saved in database.
SavingHook call before save model(new or existed model) into database.
UpdatedHook call after model updated.
UpdatingHook call when before updating model.

# Type aliases

TransactionFunc is handler to manage transaction.