Skip to main content

Overview

The users package provides functions for creating and retrieving user records from MongoDB. All functions interact with the users collection. Source: backend/users/model.go

Functions

CreateNewUser

Creates a new user document in the MongoDB users collection.

Method Signature

func (u *User) CreateNewUser() error
Source: backend/users/model.go:24-30

Description

Instance method on the User struct that inserts the user document into the database.

Usage

user := users.User{
    ID:        uuid.New().String(),
    Email:     "[email protected]",
    Password:  hashedPassword,
    Status:    "pending",
    CreatedAt: time.Now(),
}

err := user.CreateNewUser()
if err != nil {
    // Handle error (duplicate email, database connection, etc.)
}

Return Value

error
error
Returns nil on success, or an error if:
  • Database connection fails
  • Duplicate email (unique constraint violation)
  • Invalid document structure
  • MongoDB write errors

Implementation Details

func (u *User) CreateNewUser() error {
    _, err := configs.StoreRequestInDb(*u, "users")
    if err != nil {
        return err
    }
    return nil
}
  • Uses configs.StoreRequestInDb() helper function
  • Stores in users collection
  • No validation performed at this level
Validation should be performed before calling this function (e.g., email format, password strength).

GetUserById

Retrieves a user by their unique ID.

Function Signature

func GetUserById(id string) User
Source: backend/users/model.go:32-36

Parameters

id
string
required
User’s unique identifier (UUID)

Return Value

User
User
Returns the User struct. If not found, returns an empty User struct (all fields are zero values).
This function does not return an error. If the user is not found, an empty User struct is returned. Check if user.ID is non-empty to verify the user exists.

Usage

user := users.GetUserById("a1b2c3d4-e5f6-7890-abcd-ef1234567890")

if user.ID == "" {
    // User not found
} else {
    // User found
    fmt.Println(user.Email)
}

Implementation Details

func GetUserById(id string) User {
    var user User
    _ = configs.MI.DB.Collection("users").FindOne(context.TODO(), bson.M{"_id": id}).Decode(&user)
    return user
}
  • Queries MongoDB users collection
  • Uses _id field for lookup
  • Error is intentionally ignored (returns empty struct on error)
  • Uses context.TODO() (should use timeout context in production)

GetUserByEmail

Retrieves a user by their email address.

Function Signature

func GetUserByEmail(email string) (User, error)
Source: backend/users/model.go:47-54

Parameters

email
string
required
User’s email address

Return Values

User
User
The User struct if found
error
error
  • nil on success
  • mongo.ErrNoDocuments if user not found
  • Other MongoDB errors (connection, query errors)

Usage

user, err := users.GetUserByEmail("[email protected]")
if err != nil {
    if err == mongo.ErrNoDocuments {
        // User not found
    } else {
        // Database error
    }
    return
}

// User found
fmt.Println(user.ID)

Implementation Details

func GetUserByEmail(email string) (User, error) {
    var user User
    err := configs.MI.DB.Collection("users").FindOne(context.TODO(), bson.M{"email": email}).Decode(&user)
    if err != nil {
        return user, err
    }
    return user, nil
}
  • Queries MongoDB users collection
  • Uses email field for lookup
  • Returns proper error handling
  • Uses context.TODO() (should use timeout context in production)

Common Use Cases

  1. Login authentication - Verify email exists before password check
  2. Registration validation - Check if email is already registered
  3. Password reset - Verify email for password reset flow

GetUserByPhone

Retrieves a user by their phone number.

Function Signature

func GetUserByPhone(phone string) (User, error)
Source: backend/users/model.go:38-45

Parameters

phone
string
required
User’s phone number

Return Values

User
User
The User struct if found
error
error
  • nil on success
  • mongo.ErrNoDocuments if user not found
  • Other MongoDB errors (connection, query errors)

Usage

user, err := users.GetUserByPhone("+1234567890")
if err != nil {
    if err == mongo.ErrNoDocuments {
        // User not found
    } else {
        // Database error
    }
    return
}

// User found
fmt.Println(user.Email)

Implementation Details

func GetUserByPhone(phone string) (User, error) {
    var user User
    err := configs.MI.DB.Collection("users").FindOne(context.TODO(), bson.M{"phone": phone}).Decode(&user)
    if err != nil {
        return user, err
    }
    return user, nil
}
  • Queries MongoDB users collection
  • Uses phone field for lookup
  • Returns proper error handling
  • Uses context.TODO() (should use timeout context in production)

Common Use Cases

  1. Phone-based login - Alternative authentication method
  2. SMS verification - Lookup user for SMS OTP delivery
  3. Phone uniqueness check - Prevent duplicate phone registrations

Database Context

All functions use context.TODO() for MongoDB operations. For production applications, consider using context.WithTimeout():
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

err := configs.MI.DB.Collection("users").FindOne(ctx, bson.M{"email": email}).Decode(&user)

Error Handling Patterns

GetUserById (No Error Return)

user := GetUserById(id)
if user.ID == "" {
    // User not found or error occurred
}

GetUserByEmail / GetUserByPhone (With Error Return)

user, err := GetUserByEmail(email)
if err != nil {
    if errors.Is(err, mongo.ErrNoDocuments) {
        // User not found
    } else {
        // Database error
    }
}

MongoDB Queries

All query operations use MongoDB’s native query format (bson.M):
FunctionMongoDB Query
GetUserById{"_id": "<id>"}
GetUserByEmail{"email": "<email>"}
GetUserByPhone{"phone": "<phone>"}

Performance Considerations

Indexes

For optimal performance, create indexes on frequently queried fields:
// MongoDB shell commands
db.users.createIndex({ "email": 1 }, { unique: true })
db.users.createIndex({ "phone": 1 })
db.users.createIndex({ "_id": 1 }) // Automatic

Query Optimization

  • _id queries are fastest (primary key)
  • Email queries benefit from unique index
  • Phone queries benefit from index
  • Consider compound indexes for complex queries

Complete Usage Example

User Registration Flow

package main

import (
    "backend/users"
    "github.com/google/uuid"
    "golang.org/x/crypto/bcrypt"
    "time"
)

func registerUser(email, password string) error {
    // Check if email already exists
    _, err := users.GetUserByEmail(email)
    if err == nil {
        return fmt.Errorf("email already registered")
    }
    
    // Hash password
    hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 14)
    if err != nil {
        return err
    }
    
    // Create user
    user := users.User{
        ID:        uuid.New().String(),
        Email:     email,
        Password:  hashedPassword,
        Status:    "pending",
        CreatedAt: time.Now(),
    }
    
    // Save to database
    return user.CreateNewUser()
}

User Login Flow

func authenticateUser(email, password string) (users.User, error) {
    // Get user by email
    user, err := users.GetUserByEmail(email)
    if err != nil {
        return users.User{}, fmt.Errorf("invalid credentials")
    }
    
    // Check status
    if user.Status != "active" {
        return users.User{}, fmt.Errorf("account not active")
    }
    
    // Verify password
    err = bcrypt.CompareHashAndPassword(user.Password, []byte(password))
    if err != nil {
        return users.User{}, fmt.Errorf("invalid credentials")
    }
    
    return user, nil
}

Build docs developers (and LLMs) love