Database
MongoDB models, schemas, and database configuration
Fastly uses MongoDB with Mongoose ODM. All models are located in src/models/.
Data Model Overview
The application uses three main collections:
| Collection | Purpose |
|---|---|
userauths | Authentication credentials and verification tokens |
users | User profile information |
usersessions | Active and revoked session records |
Relationships
- Each
UserAuthhas oneUserprofile (created after email verification) - Each
UserAuthcan have multipleUserSessiondocuments
Model Files
users.ts
user-sessions.ts
UserAuth Model
Stores authentication credentials and verification tokens.
Collection: userauths
File: src/models/users.ts
Schema
Prop
Type
Schema Definition
const userAuthSchema = new mongoose.Schema(
{
firstName: { type: String, default: null },
lastName: { type: String, default: null },
email: {
type: String,
required: true,
unique: true,
lowercase: true,
trim: true,
index: true,
},
password: { type: String, default: null },
isVerified: { type: Boolean, default: false, index: true },
authMethod: {
type: String,
enum: ['email', 'google', 'github', 'facebook'],
required: true,
},
verificationCode: { type: String, default: null },
verificationCodeExpiresAt: { type: Date, default: null },
resetPasswordToken: { type: String, default: null },
resetPasswordTokenExpiresAt: { type: Date, default: null },
},
{ timestamps: true }
);User Model
Stores user profile information.
Collection: users
File: src/models/users.ts
Schema
Prop
Type
Location Object
interface Location {
address: string;
city: string;
state: string;
country: string;
zipCode: string;
}Social Accounts Array
interface SocialAccount {
url: string;
provider: string;
}Preferences Object
interface Preferences {
theme: 'light' | 'dark' | 'system';
font: 'sans' | 'serif' | 'mono' | 'system';
}Schema Definition
const userSchema = new mongoose.Schema(
{
userAuth: {
type: mongoose.Schema.Types.ObjectId,
ref: 'UserAuth',
required: true,
index: true,
},
firstName: { type: String, required: true },
lastName: { type: String, required: true },
email: {
type: String,
required: true,
unique: true,
lowercase: true,
index: true,
},
username: {
type: String,
required: true,
unique: true,
lowercase: true,
index: true,
},
avatar: { type: String, default: null },
bio: { type: String, default: null, maxLength: 200 },
location: {
address: String,
city: String,
state: String,
country: String,
zipCode: String,
},
socialAccounts: [
{
url: String,
provider: String,
},
],
hasChangedUsername: { type: Boolean, default: false },
preferences: {
theme: {
type: String,
enum: ['light', 'dark', 'system'],
default: 'system',
},
font: {
type: String,
enum: ['sans', 'serif', 'mono', 'system'],
default: 'system',
},
},
dob: { type: Date, default: null },
},
{ timestamps: true }
);UserSession Model
Tracks active and revoked user sessions.
Collection: usersessions
File: src/models/user-sessions.ts
Schema
Prop
Type
Schema Definition
const userSessionSchema = new mongoose.Schema({
userAuth: {
type: mongoose.Schema.Types.ObjectId,
ref: 'UserAuth',
required: true,
index: true,
},
sessionId: {
type: String,
required: true,
unique: true,
index: true,
},
authMethod: {
type: String,
enum: ['email', 'google', 'github'],
required: true,
},
userAgent: { type: String },
browser: { type: String },
os: { type: String },
device: { type: String },
ipAddress: { type: String },
location: { type: String, default: null },
createdAt: { type: Date, default: Date.now, immutable: true },
lastActiveAt: { type: Date, default: Date.now },
revokedAt: { type: Date, default: null, index: true },
});
// Compound index for efficient session queries
userSessionSchema.index({ userAuth: 1, revokedAt: 1 });Database Indexes
Proper indexing ensures efficient queries:
// UserAuth indexes
{ email: 1 } // unique
{ isVerified: 1 }
// User indexes
{ email: 1 } // unique
{ username: 1 } // unique
{ userAuth: 1 }
// UserSession indexes
{ sessionId: 1 } // unique
{ userAuth: 1 }
{ revokedAt: 1 }
{ userAuth: 1, revokedAt: 1 } // compoundDatabase Connection
File: src/lib/config/db-connect.ts
import mongoose from 'mongoose';
const MONGODB_URI = process.env.MONGODB_URI!;
if (!MONGODB_URI) {
throw new Error('Please define MONGODB_URI in environment variables');
}
let cached = global.mongoose;
if (!cached) {
cached = global.mongoose = { conn: null, promise: null };
}
export async function connectDB() {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
cached.promise = mongoose.connect(MONGODB_URI, {
bufferCommands: false,
connectTimeoutMS: 5000,
serverSelectionTimeoutMS: 5000,
});
}
cached.conn = await cached.promise;
return cached.conn;
}The connection is cached globally to prevent creating multiple connections during development hot reloads.
Common Queries
Find user by email
const userAuth = await UserAuth.findOne({ email: email.toLowerCase() });Find user with profile
const user = await User.findOne({ userAuth: userAuthId })
.populate('userAuth', 'authMethod isVerified');Get active sessions
const sessions = await UserSession.find({
userAuth: userAuthId,
revokedAt: null,
}).sort({ lastActiveAt: -1 });Update session activity
await UserSession.updateOne(
{ userAuth: userAuthId, sessionId, revokedAt: null },
{ $set: { lastActiveAt: new Date() } }
);Revoke session
await UserSession.updateOne(
{ userAuth: userAuthId, sessionId },
{ $set: { revokedAt: new Date() } }
);For extending the database schema with custom fields, see the Customization guide.