Quick Start¶
In this 5-minute tutorial, we'll build a simple Go application that connects to MongoDB, defines a user and a post model, and demonstrates basic CRUD operations using Goose.
1. Connect to MongoDB¶
Use the goose.Connect function to establish a connection. Goose provides functional options to configure your client.
package main
import (
"context"
"fmt"
"log"
"github.com/devsamahd/goose"
)
func main() {
ctx := context.Background()
// Connect to MongoDB
client, err := goose.Connect(ctx, "mongodb://localhost:27017", goose.WithDatabase("goose_quickstart"))
if err != nil {
log.Fatal(err)
}
defer client.Disconnect(ctx)
fmt.Println("Connected to MongoDB!")
}
Context First
Notice that ctx context.Context is passed as the first argument. Goose embraces idiomatic Go by putting context first for all I/O operations.
2. Define Your Structs¶
Let's define a User and a Post document. Use bson tags for MongoDB mapping and goose tags for validation and relationships.
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type User struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
Name string `bson:"name" goose:"required"`
Email string `bson:"email" goose:"required,unique"`
Age int `bson:"age" goose:"min=18"`
Posts []primitive.ObjectID `bson:"posts" goose:"ref=Post"`
CreatedAt time.Time `bson:"createdAt"`
}
type Post struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
Title string `bson:"title"`
Content string `bson:"content"`
Author primitive.ObjectID `bson:"author" goose:"ref=User"`
}
3. Create Models¶
Models provide the type-safe CRUD interface for your structs. We need to create a schema and bind it to a model.
// Create a schema for User
userSchema := goose.NewSchema()
// Add a hook to set CreatedAt automatically
userSchema.PreSave(func(ctx context.Context, doc interface{}) error {
user := doc.(*User)
if user.CreatedAt.IsZero() {
user.CreatedAt = time.Now()
}
return nil
})
// Initialize Models
userModel := goose.NewModel[User](client, "users", userSchema)
postModel := goose.NewModel[Post](client, "posts", goose.NewSchema())
4. Insert Documents¶
Let's create a user and assign a post to them.
// Create a new User
user := &User{
Name: "Jane Doe",
Email: "jane@example.com",
Age: 28,
}
insertRes, err := userModel.Create(ctx, user)
if err != nil {
log.Fatal(err)
}
// Create a new Post linked to the user
post := &Post{
Title: "Hello Goose",
Content: "My very first post using the Goose ODM!",
Author: insertRes.InsertedID.(primitive.ObjectID),
}
if _, err := postModel.Create(ctx, post); err != nil {
log.Fatal(err)
}
5. Query and Populate¶
One of Goose's most powerful features is chaining query builders and population (resolving references).
import "go.mongodb.org/mongo-driver/bson"
// Find a user by email and populate their posts
var foundUser User
err = userModel.FindOne(bson.M{"email": "jane@example.com"}).
Populate("Posts").
Exec(ctx, &foundUser)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Welcome, %s!\n", foundUser.Name)
Congratulations!
You have successfully connected to MongoDB, created schemas with hooks, and performed type-safe populated queries!
Check out the Configuration page to learn more about setting up Goose.