Các mẫu tối ưu cho cơ sở dữ liệu NoSQL (MongoDB, Redis và hệ phân tán đa).
Expert patterns for working with NoSQL databases (MongoDB, Redis, DynamoDB, etc.)
// ✅ Good - Embedded for 1-to-few
{
_id: ObjectId("..."),
name: "John Doe",
email: "[email protected]",
addresses: [
{ street: "123 Main", city: "NYC", zip: "10001" },
{ street: "456 Oak", city: "LA", zip: "90001" }
]
}
// ✅ Good - Referenced for 1-to-many
{
_id: ObjectId("..."),
title: "Post Title",
authorId: ObjectId("..."), // Reference to User
comments: [ObjectId("..."), ObjectId("...")] // References
}
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: {
_id: "$userId",
totalSpent: { $sum: "$amount" },
orderCount: { $sum: 1 }
}},
{ $sort: { totalSpent: -1 } },
{ $limit: 10 }
]);
async function getUser(userId) {
// Try cache first
const cached = await redis.get(`user:${userId}`);
if (cached) return JSON.parse(cached);
// Cache miss - fetch from DB
const user = await db.users.findById(userId);
// Store in cache (TTL: 1 hour)
await redis.setex(`user:${userId}`, 3600, JSON.stringify(user));
return user;
}
// Counter
await redis.incr('page:views');
// Set (unique items)
await redis.sadd('users:online', userId);
await redis.sismember('users:online', userId);
// Sorted Set (leaderboard)
await redis.zadd('leaderboard', score, userId);
await redis.zrevrange('leaderboard', 0, 9); // Top 10
❌ Treating NoSQL like SQL → Embrace denormalization
❌ No indexing → Critical for performance
❌ Deep nesting → Limit to 2-3 levels
❌ Large arrays → Use references for > 100 items
❌ No TTL on cache → Memory leaks
✅ Embed for 1-to-few, reference for 1-to-many
✅ Index frequently queried fields
✅ Use aggregation pipelines for complex queries
✅ Implement caching layer (Redis)
✅ Set TTL on cached data
✅ Monitor query performance
Use NoSQL when:
Use SQL when: