marango
marango is an ODM (Object Document Mapper) for MongoDB written in Go. It is written on top of the mgo library.
marango doesn't try to replace mgo, but rather simply augments it.
####Why do I we need an ODM?
You don't. Though, it is nice to have.. specially in the context of a web application. It allows you to couple your business logic with your data. But it is only useful as long as it doesn't get in your way, and you can drop down the to the DB driver any time.
Features :
-
Populate - MongoDB doesn't have JOINs, but we still want to query based on relationships. marango makes this task easy. Relationships are mapped via tags in the model definition. marango can run populate on a single ObjectId or a slice of them. And it can even run queries on these relationships! For example, lets say you have a social networking site and a user has 200 friends, you can run a query on those friends to only return the friends that are older than 30, sort them by their ages, and limit it to 5 results
-
Hooks - The hooks functionality allows you to register functions to be called before or after an action has taken place on the document. Ex: PreSave(), PreRemove()
. Use these to consolidate your business logic in one place. See bellow for a full list of supported hooks
-
Virtuals - Store computed and temporary data along with your document. These values live only for the lifetime of the document, and are not persisted to the database.
-
Extends mgo.Collection - marango extends mgo's Collection struct. Reimplements operations that take just a bson.ObjectId to also accept string, because often times we only have a string representation of the ObjectId and we can let marango handle the conversion. Mgo's Query struct is replaced with one that understands the populate functions.
-
Convenience methods - All documents get methods such as Save(), Remove(), Apply(), Populate(), PopulateQuery()
API Docs
The docs include lots of detailed explainations and examples:
In all of its glory: http://godoc.org/github.com/mansoor-s/marango
Usage:
Note:
marango suppresses mgo's ErrNotFound error and instead provides the method IsValid() on every document. It returns true if the document was found, otherwise returns false
Define your Model:
package Models
type User struct {
marango.Document `bson:"-"`
Id bson.ObjectId `bson:"_id"`
Email string
Password string
Friends []bson.ObjectId `model:"User"`
}
func (u *User) OnResult() {
u.Virtual.SetInt("totalFriends", len(u.Friends))
}
func (u *User) MySuperDuperMethod() {
}
Implementation:
package main
import (
"github.com/dsmontoya/marango"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
func main() {
session, err := mgo.Dial("localhost")
if err != nil {
panic(err)
}
defer session.Close()
mago := marango.New(session, "MY_DB_NAME")
User := mago.Register(User{}, "MY_COLLECTION_NAME")
user := &User{}
err = mago.FindId("5232171fc081671e81000001").Exec(user)
if err != nil {
}
if !user.IsValid() {
}
users := []*User{}
User.Find(bson.M{"age": 40, "planet": "Earth"}).Sort("firstname", "-lastname").Limit(10).Exec(&users)
users := []*User{}
User.Find(bson.M{"age": 40}).Sort("firstname").Limit(10).Populate("Friends").Exec(&users)
theFirstUser := users[0]
thisUsersFriends := []*User{}
theFirstUser.Populated("Friends", thisUsersFriends)
friends := []*User{}
popQuery := User.Find(bson.M{"age": bson.M{"$gt": 30}}).Sort("age").Limit(5)
err := myDoc.PopulateQuery(popQuery, friends)
User.EnsureIndex(.....)
User.UpdateAll(.....)
User.Count()
}
###Hooks (Hooks are optional):
PreSave()
PostSave()
PreRemove()
PostRemove()
OnCreate()
OnResult()
Implement these methods in your schema and they will be called when triggered.
Look at the API docs for marango.Document for more info
###Virtuals
Example Usage:
myDoc.Virtual.SetString("stringVal", "ABCDEF")
myDoc.Virtual.Set("myIds", myIds)
idsInterface, ok := myDoc.Virtual.Get("myIds")
if !ok {
}
myIds := idsInterface.([]bson.ObjectId)