MongoDB Usage Guidelines
Full documentation: docs/mongodb-usage.md
Quick Reference
Core Principles
- •All MongoDB operations in
src/server/database/collections/ - •Never import
mongodbdirectly in API handlers - •Use
@/server/utilsfor ID conversion
ID Utilities
typescript
import { toStringId, toQueryId, toDocumentId } from '@/server/utils';
// API responses
{ _id: toStringId(doc._id) }
// MongoDB queries
{ _id: toQueryId(clientId) }
// Document insertion
{ _id: toDocumentId(clientId) }
⚠️ CRITICAL: Schema Backward Compatibility
When adding new fields to schemas, existing documents won't have them. Always use optional chaining and fallbacks:
typescript
// ✅ CORRECT - Handle potentially missing fields const createdAt = doc.createdAt?.toISOString() ?? new Date().toISOString(); const firstOccurrence = doc.firstOccurrence?.toISOString() ?? createdAt; const count = doc.count ?? 1; // ❌ WRONG - Assumes field always exists (crashes on legacy docs) const createdAt = doc.createdAt.toISOString();
When Adding New Fields:
- •Add as optional in TypeScript (
?) or provide defaults - •Use optional chaining (
?.) when accessing - •Provide fallbacks with nullish coalescing (
??) - •Consider migration scripts for critical fields
See docs/mongodb-usage.md for full details.
What NOT To Do
❌ NEVER import MongoDB directly in API layer:
typescript
// WRONG - This is forbidden
import { MongoClient, Collection } from 'mongodb';
const getExercises = async () => {
const client = new MongoClient(process.env.MONGODB_URI!);
const db = client.db('training_app');
const collection = db.collection('exercises');
return collection.find().toArray();
};
❌ NEVER access collections directly from API layer:
typescript
// WRONG - This is forbidden
import { getDb } from '@/server/database';
const getExercises = async () => {
const db = await getDb();
const collection = db.collection('exercises');
return collection.find().toArray();
};
❌ NEVER use direct ObjectId methods on IDs that could be UUIDs:
typescript
// WRONG - Will crash on UUID strings from client-generated IDs
const response = {
_id: doc._id.toHexString(), // TypeError: toHexString is not a function
};
const item = await collection.findOne({
_id: new ObjectId(clientId), // BSONError: invalid ObjectId
});
// CORRECT - Use server utilities
import { toStringId, toQueryId } from '@/server/utils';
const response = {
_id: toStringId(doc._id), // Works for both ObjectId and string
};
const item = await collection.findOne({
_id: toQueryId(clientId), // Works for both formats
});
Reference
- •Server Utilities:
src/server/utils/id.ts - •Mutation Guidelines:
docs/react-query-mutations.md(client-generated IDs)