Overview
The backend uses MongoDB as its primary database with the official go.mongodb.org/mongo-driver. The configs package handles all database initialization and common operations.
MongoDB Connection
MongoInstance Struct
The global database instance is defined in configs/db.go:14-19:
type MongoInstance struct {
Client * mongo . Client
DB * mongo . Database
}
var MI MongoInstance
MongoDB client instance for connection management
Active database reference for queries
The MI variable is a global singleton that provides database access throughout the application.
Connection Initialization
The ConnectDB function establishes the MongoDB connection (configs/db.go:21-44):
func ConnectDB () {
dbName := fmt . Sprintf ( " %s -backend" , AppEnv ())
serverAPI := options . ServerAPI ( options . ServerAPIVersion1 )
opts := options . Client (). ApplyURI ( EnvMongoURI ()). SetServerAPIOptions ( serverAPI )
client , err := mongo . Connect ( context . TODO (), opts )
if err != nil {
log . Fatalf ( err . Error ())
}
// defer func() {
// if err = client.Disconnect(context.TODO()); err != nil {
// panic(err)
// }
// }()
var result bson . M
if err := client . Database ( dbName ). RunCommand ( context . TODO (), bson . D {{ Key : "ping" , Value : 1 }}). Decode ( & result ); err != nil {
log . Fatalf ( err . Error ())
}
fmt . Println ( "Pinged your deployment. You successfully connected to MongoDB!" )
MI = MongoInstance {
Client : client ,
DB : client . Database ( dbName ),
}
}
Connection Flow
Database Naming - Dynamically sets database name as {APP_ENV}-backend (e.g., development-backend, production-backend)
Server API Options - Uses MongoDB Server API Version 1 for stable compatibility
Connection Attempt - Connects using URI from environment variable
Health Check - Pings database to verify connection
Global Instance - Stores client and database in MI variable
The disconnection logic is commented out. In production, consider implementing graceful shutdown with defer client.Disconnect() in the main function.
Environment Configuration
Database configuration is retrieved from environment variables (configs/env.go):
MongoDB URI
func EnvMongoURI () string {
return os . Getenv ( "MONGODB_URI" )
}
MongoDB connection string. Supports local MongoDB or MongoDB Atlas.
Examples:
# Local MongoDB
MONGODB_URI = mongodb://localhost:27017
# MongoDB Atlas
MONGODB_URI = mongodb+srv://user:[email protected] /? retryWrites = true & w = majority
# MongoDB with authentication
MONGODB_URI = mongodb://username:password@localhost:27017/admin
Application Environment
func AppEnv () string {
return os . Getenv ( "APP_ENV" )
}
func EnvIsProd () bool {
return AppEnv () == "production"
}
Application environment (development, staging, or production). Affects database naming.
Database Operations
Insert Document
The StoreRequestInDb function inserts documents into collections (configs/db.go:46-58):
func StoreRequestInDb ( request any , collection string ) ( string , error ) {
coll := MI . DB . Collection ( collection )
insertResult , err := coll . InsertOne ( context . TODO (), request )
if err != nil {
log . Printf ( "there was an error recording the request \n %v \n " , err )
return "" , err
}
uuid , ok := insertResult . InsertedID .( primitive . ObjectID )
if ! ok {
return "" , err
}
return uuid . Hex (), nil
}
The document to insert (typically a struct)
Target collection name (e.g., "users", "sessions")
Returns: Hexadecimal string of the inserted document’s ObjectID
Usage Example:
user := users . User {
Email : "[email protected] " ,
Status : "active" ,
CreatedAt : time . Now (),
}
id , err := configs . StoreRequestInDb ( user , "users" )
if err != nil {
// Handle error
}
// id contains the MongoDB ObjectID as hex string
Update Document
The UpdateRequestInDb function updates existing documents (configs/db.go:60-70):
func UpdateRequestInDb ( ID string , request any , collection string ) ( string , error ) {
coll := MI . DB . Collection ( collection )
filter := bson . M { "_id" : ID }
update := bson . M { "$set" : request }
_ , err := coll . UpdateOne ( context . TODO (), filter , update )
if err != nil {
log . Printf ( "there was an error updating the request \n %v \n " , err )
return "" , err
}
return ID , nil
}
Document identifier (must match the _id field)
Document fields to update (uses $set operator)
Returns: The document ID if update succeeds
This function expects the _id field to be a string, not a MongoDB ObjectID. Ensure your documents use string IDs or modify the filter accordingly.
Usage Example:
updateData := bson . M {
"status" : "active" ,
"updated_at" : time . Now (),
}
id , err := configs . UpdateRequestInDb ( userID , updateData , "users" )
if err != nil {
// Handle error
}
Query Operations
While the configs package provides insert and update utilities, query operations are typically handled in model packages. Example from users/model.go:32-36:
func GetUserById ( id string ) User {
var user User
_ = configs . MI . DB . Collection ( "users" ). FindOne ( context . TODO (), bson . M { "_id" : id }). Decode ( & user )
return user
}
Common Query Patterns
Find One
Find Many
Delete
Count
// Find single document
var user User
err := configs . MI . DB . Collection ( "users" ). FindOne (
context . TODO (),
bson . M { "email" : "[email protected] " },
). Decode ( & user )
BSON Types
MongoDB uses BSON (Binary JSON) for document storage. Common BSON types:
Unordered map for documents and queries
Ordered document (preserves field order)
MongoDB’s unique identifier type
Usage:
// Simple query
filter := bson . M { "email" : "[email protected] " }
// Complex query with operators
filter := bson . M {
"status" : "active" ,
"created_at" : bson . M { "$gte" : time . Now (). AddDate ( 0 , - 1 , 0 )},
}
// Ordered document (for commands)
cmd := bson . D {{ Key : "ping" , Value : 1 }}
Context Management
The codebase currently uses context.TODO() for database operations. For production applications, consider using context with timeouts:
// Create context with 5-second timeout
ctx , cancel := context . WithTimeout ( context . Background (), 5 * time . Second )
defer cancel ()
// Use in database operation
err := configs . MI . DB . Collection ( "users" ). FindOne ( ctx , filter ). Decode ( & user )
Using context.WithTimeout() prevents database operations from hanging indefinitely and improves application resilience.
Collections Used
Current collections in the application:
User accounts and authentication data
Collections are created automatically when first accessed. MongoDB creates them lazily on first write operation.
Connection String Examples
Local Development
MONGODB_URI = mongodb://localhost:27017
Docker Compose
MONGODB_URI = mongodb://mongo:27017
MongoDB Atlas
MONGODB_URI = mongodb+srv:// < username > : < password > @cluster0.example.mongodb.net/? retryWrites = true & w = majority
Authentication Required
MONGODB_URI = mongodb://admin:password@localhost:27017/admin? authSource = admin
Error Handling
Database operations should handle errors appropriately:
// Connection errors - Fatal (app cannot run without DB)
if err != nil {
log . Fatalf ( "Failed to connect to database: %v " , err )
}
// Query errors - Return to caller
if err != nil {
return nil , fmt . Errorf ( "failed to fetch user: %w " , err )
}
// Insert/Update errors - Log and return
if err != nil {
log . Printf ( "Database operation failed: %v " , err )
return "" , err
}
Avoid using log.Fatalf() for query errors as it terminates the entire application. Reserve fatal logging for initialization failures only.
Database Naming Convention
Databases are automatically named based on environment:
dbName := fmt . Sprintf ( " %s -backend" , AppEnv ())
APP_ENV Database Name developmentdevelopment-backendstagingstaging-backendproductionproduction-backend
This convention ensures environment isolation and prevents accidental data mixing.
Indexes
No indexes are explicitly defined in the codebase. Consider adding indexes for frequently queried fields:
// Create unique index on email field
indexModel := mongo . IndexModel {
Keys : bson . D {{ Key : "email" , Value : 1 }},
Options : options . Index (). SetUnique ( true ),
}
_ , err := configs . MI . DB . Collection ( "users" ). Indexes (). CreateOne ( context . TODO (), indexModel )
Next Steps
User Model Explore the User struct and its database operations
Authentication See how authentication uses database queries