- 发布于
MongoDB 数据库设计与优化:NoSQL 数据库最佳实践
- 作者

- 姓名
- 全能波
- GitHub
- @weicracker
MongoDB 数据库设计与优化:NoSQL 数据库最佳实践
MongoDB 是一个强大的 NoSQL 文档数据库,为现代应用提供了灵活的数据存储解决方案。本文将深入探讨 MongoDB 的设计原则、优化策略和最佳实践。
MongoDB 基础概念
文档数据模型
// 用户文档示例
const userDocument = {
_id: ObjectId('507f1f77bcf86cd799439011'),
username: 'john_doe',
email: 'john@example.com',
profile: {
firstName: 'John',
lastName: 'Doe',
age: 30,
avatar: 'https://example.com/avatar.jpg',
},
preferences: {
theme: 'dark',
language: 'zh-CN',
notifications: {
email: true,
push: false,
sms: true,
},
},
addresses: [
{
type: 'home',
street: '123 Main St',
city: 'Beijing',
country: 'China',
zipCode: '100000',
},
{
type: 'work',
street: '456 Business Ave',
city: 'Shanghai',
country: 'China',
zipCode: '200000',
},
],
tags: ['developer', 'mongodb', 'javascript'],
createdAt: new Date('2024-01-01T00:00:00Z'),
updatedAt: new Date('2024-03-10T12:00:00Z'),
isActive: true,
}
// 博客文章文档示例
const postDocument = {
_id: ObjectId('507f1f77bcf86cd799439012'),
title: 'MongoDB 最佳实践',
slug: 'mongodb-best-practices',
content: '这是一篇关于 MongoDB 的文章...',
excerpt: '学习 MongoDB 的最佳实践',
author: {
_id: ObjectId('507f1f77bcf86cd799439011'),
username: 'john_doe',
name: 'John Doe',
},
categories: ['数据库', 'NoSQL', 'MongoDB'],
tags: ['mongodb', 'database', 'nosql'],
metadata: {
wordCount: 1500,
readingTime: 8,
difficulty: 'intermediate',
},
seo: {
metaTitle: 'MongoDB 最佳实践指南',
metaDescription: '深入学习 MongoDB 数据库设计和优化',
keywords: ['mongodb', 'nosql', 'database'],
},
stats: {
views: 1250,
likes: 89,
shares: 23,
comments: 15,
},
publishedAt: new Date('2024-03-01T10:00:00Z'),
createdAt: new Date('2024-02-28T15:30:00Z'),
updatedAt: new Date('2024-03-10T09:15:00Z'),
status: 'published',
}
集合设计原则
// 1. 嵌入式文档 vs 引用
// 适合嵌入的场景:一对一、一对少量
const orderWithEmbeddedItems = {
_id: ObjectId('...'),
orderNumber: 'ORD-2024-001',
customer: {
_id: ObjectId('...'),
name: '张三',
email: 'zhang@example.com',
},
items: [
{
productId: ObjectId('...'),
name: 'MacBook Pro',
price: 12999,
quantity: 1,
},
{
productId: ObjectId('...'),
name: 'Magic Mouse',
price: 599,
quantity: 1,
},
],
total: 13598,
status: 'completed',
createdAt: new Date(),
}
// 适合引用的场景:一对多、多对多
const userWithPostReferences = {
_id: ObjectId('...'),
username: 'author123',
email: 'author@example.com',
// 不嵌入所有文章,而是通过查询获取
postCount: 150,
createdAt: new Date(),
}
const postWithAuthorReference = {
_id: ObjectId('...'),
title: '我的第一篇文章',
content: '...',
authorId: ObjectId('...'), // 引用用户ID
createdAt: new Date(),
}
// 2. 反范式化设计
const commentWithDenormalizedData = {
_id: ObjectId('...'),
postId: ObjectId('...'),
postTitle: 'MongoDB 最佳实践', // 冗余数据,避免额外查询
content: '很好的文章!',
author: {
_id: ObjectId('...'),
username: 'reader123',
avatar: 'https://example.com/avatar.jpg', // 冗余数据
},
createdAt: new Date(),
}
查询操作与优化
1. 基础查询操作
// 连接 MongoDB
const { MongoClient } = require('mongodb')
class MongoDBService {
constructor(uri, dbName) {
this.client = new MongoClient(uri)
this.dbName = dbName
this.db = null
}
async connect() {
await this.client.connect()
this.db = this.client.db(this.dbName)
console.log('MongoDB 连接成功')
}
async disconnect() {
await this.client.close()
console.log('MongoDB 连接已关闭')
}
// 基础查询
async findUsers(filter = {}, options = {}) {
const collection = this.db.collection('users')
return await collection.find(filter, options).toArray()
}
// 分页查询
async findUsersWithPagination(filter = {}, page = 1, limit = 10) {
const collection = this.db.collection('users')
const skip = (page - 1) * limit
const [users, total] = await Promise.all([
collection.find(filter).skip(skip).limit(limit).sort({ createdAt: -1 }).toArray(),
collection.countDocuments(filter),
])
return {
users,
pagination: {
page,
limit,
total,
pages: Math.ceil(total / limit),
},
}
}
// 复杂查询
async findPostsWithFilters(filters) {
const collection = this.db.collection('posts')
const query = {}
// 文本搜索
if (filters.search) {
query.$text = { $search: filters.search }
}
// 分类筛选
if (filters.category) {
query.categories = filters.category
}
// 标签筛选
if (filters.tags && filters.tags.length > 0) {
query.tags = { $in: filters.tags }
}
// 日期范围
if (filters.dateFrom || filters.dateTo) {
query.publishedAt = {}
if (filters.dateFrom) {
query.publishedAt.$gte = new Date(filters.dateFrom)
}
if (filters.dateTo) {
query.publishedAt.$lte = new Date(filters.dateTo)
}
}
// 状态筛选
if (filters.status) {
query.status = filters.status
}
return await collection.find(query).sort({ publishedAt: -1 }).toArray()
}
// 聚合查询
async getPostStatistics() {
const collection = this.db.collection('posts')
return await collection
.aggregate([
{
$match: { status: 'published' },
},
{
$group: {
_id: {
year: { $year: '$publishedAt' },
month: { $month: '$publishedAt' },
},
count: { $sum: 1 },
totalViews: { $sum: '$stats.views' },
avgViews: { $avg: '$stats.views' },
},
},
{
$sort: { '_id.year': -1, '_id.month': -1 },
},
{
$project: {
_id: 0,
year: '$_id.year',
month: '$_id.month',
count: 1,
totalViews: 1,
avgViews: { $round: ['$avgViews', 2] },
},
},
])
.toArray()
}
}
2. 高级聚合操作
// 复杂聚合管道
class AdvancedQueries {
constructor(db) {
this.db = db
}
// 用户活跃度分析
async getUserActivityAnalysis() {
const collection = this.db.collection('users')
return await collection
.aggregate([
{
$lookup: {
from: 'posts',
localField: '_id',
foreignField: 'authorId',
as: 'posts',
},
},
{
$lookup: {
from: 'comments',
localField: '_id',
foreignField: 'authorId',
as: 'comments',
},
},
{
$addFields: {
postCount: { $size: '$posts' },
commentCount: { $size: '$comments' },
totalViews: { $sum: '$posts.stats.views' },
avgViewsPerPost: {
$cond: {
if: { $gt: [{ $size: '$posts' }, 0] },
then: { $divide: [{ $sum: '$posts.stats.views' }, { $size: '$posts' }] },
else: 0,
},
},
},
},
{
$addFields: {
activityScore: {
$add: [
{ $multiply: ['$postCount', 10] },
{ $multiply: ['$commentCount', 2] },
{ $divide: ['$totalViews', 100] },
],
},
},
},
{
$project: {
username: 1,
email: 1,
postCount: 1,
commentCount: 1,
totalViews: 1,
avgViewsPerPost: { $round: ['$avgViewsPerPost', 2] },
activityScore: { $round: ['$activityScore', 2] },
createdAt: 1,
},
},
{
$sort: { activityScore: -1 },
},
{
$limit: 50,
},
])
.toArray()
}
// 热门标签统计
async getPopularTags(limit = 20) {
const collection = this.db.collection('posts')
return await collection
.aggregate([
{
$match: { status: 'published' },
},
{
$unwind: '$tags',
},
{
$group: {
_id: '$tags',
count: { $sum: 1 },
totalViews: { $sum: '$stats.views' },
avgViews: { $avg: '$stats.views' },
recentPosts: {
$push: {
title: '$title',
slug: '$slug',
publishedAt: '$publishedAt',
},
},
},
},
{
$addFields: {
recentPosts: {
$slice: [
{
$sortArray: {
input: '$recentPosts',
sortBy: { publishedAt: -1 },
},
},
3,
],
},
},
},
{
$sort: { count: -1 },
},
{
$limit: limit,
},
{
$project: {
_id: 0,
tag: '$_id',
count: 1,
totalViews: 1,
avgViews: { $round: ['$avgViews', 2] },
recentPosts: 1,
},
},
])
.toArray()
}
// 内容推荐算法
async getRecommendedPosts(userId, limit = 10) {
const collection = this.db.collection('posts')
// 获取用户的阅读历史和偏好
const userPreferences = await this.getUserPreferences(userId)
return await collection
.aggregate([
{
$match: {
status: 'published',
authorId: { $ne: ObjectId(userId) }, // 排除自己的文章
},
},
{
$addFields: {
relevanceScore: {
$add: [
// 标签匹配分数
{
$multiply: [
{ $size: { $setIntersection: ['$tags', userPreferences.preferredTags] } },
10,
],
},
// 分类匹配分数
{
$multiply: [
{
$size: {
$setIntersection: ['$categories', userPreferences.preferredCategories],
},
},
15,
],
},
// 热度分数
{ $divide: ['$stats.views', 100] },
// 时间衰减分数
{
$multiply: [
{
$divide: [
{ $subtract: [new Date(), '$publishedAt'] },
1000 * 60 * 60 * 24, // 转换为天数
],
},
-0.1, // 负权重,越新的文章分数越高
],
},
],
},
},
},
{
$match: {
relevanceScore: { $gt: 0 },
},
},
{
$sort: { relevanceScore: -1 },
},
{
$limit: limit,
},
{
$project: {
title: 1,
slug: 1,
excerpt: 1,
author: 1,
categories: 1,
tags: 1,
stats: 1,
publishedAt: 1,
relevanceScore: { $round: ['$relevanceScore', 2] },
},
},
])
.toArray()
}
async getUserPreferences(userId) {
// 基于用户的阅读历史分析偏好
const readingHistory = await this.db
.collection('readingHistory')
.aggregate([
{
$match: { userId: ObjectId(userId) },
},
{
$lookup: {
from: 'posts',
localField: 'postId',
foreignField: '_id',
as: 'post',
},
},
{
$unwind: '$post',
},
{
$group: {
_id: null,
preferredTags: { $push: '$post.tags' },
preferredCategories: { $push: '$post.categories' },
},
},
{
$project: {
preferredTags: {
$reduce: {
input: '$preferredTags',
initialValue: [],
in: { $setUnion: ['$$value', '$$this'] },
},
},
preferredCategories: {
$reduce: {
input: '$preferredCategories',
initialValue: [],
in: { $setUnion: ['$$value', '$$this'] },
},
},
},
},
])
.toArray()
return readingHistory[0] || { preferredTags: [], preferredCategories: [] }
}
}
索引策略与优化
1. 索引设计
// 索引管理类
class IndexManager {
constructor(db) {
this.db = db
}
// 创建基础索引
async createBasicIndexes() {
const collections = {
users: [
{ email: 1 }, // 唯一索引
{ username: 1 }, // 唯一索引
{ 'profile.firstName': 1, 'profile.lastName': 1 }, // 复合索引
{ tags: 1 }, // 数组索引
{ createdAt: -1 }, // 时间索引
{ isActive: 1, createdAt: -1 }, // 复合索引
],
posts: [
{ slug: 1 }, // 唯一索引
{ authorId: 1, status: 1 }, // 复合索引
{ categories: 1 }, // 数组索引
{ tags: 1 }, // 数组索引
{ publishedAt: -1 }, // 时间索引
{ status: 1, publishedAt: -1 }, // 复合索引
{ 'stats.views': -1 }, // 嵌套字段索引
{ title: 'text', content: 'text', excerpt: 'text' }, // 文本索引
],
comments: [
{ postId: 1, createdAt: -1 }, // 复合索引
{ authorId: 1 }, // 外键索引
{ createdAt: -1 }, // 时间索引
],
}
for (const [collectionName, indexes] of Object.entries(collections)) {
const collection = this.db.collection(collectionName)
for (const index of indexes) {
try {
const options = {}
// 设置唯一索引
if (collectionName === 'users' && (index.email || index.username)) {
options.unique = true
}
if (collectionName === 'posts' && index.slug) {
options.unique = true
}
// 设置稀疏索引
if (index.publishedAt) {
options.sparse = true
}
await collection.createIndex(index, options)
console.log(`创建索引成功: ${collectionName}`, index)
} catch (error) {
console.error(`创建索引失败: ${collectionName}`, index, error.message)
}
}
}
}
// 分析查询性能
async analyzeQuery(collection, query, options = {}) {
const coll = this.db.collection(collection)
// 使用 explain 分析查询计划
const explanation = await coll.find(query, options).explain('executionStats')
const stats = explanation.executionStats
return {
executionTimeMillis: stats.executionTimeMillis,
totalDocsExamined: stats.totalDocsExamined,
totalDocsReturned: stats.totalDocsReturned,
indexesUsed: explanation.queryPlanner.winningPlan.inputStage?.indexName || 'COLLSCAN',
efficiency: stats.totalDocsReturned / stats.totalDocsExamined,
needsIndex: stats.totalDocsExamined > stats.totalDocsReturned * 10,
}
}
// 获取索引使用统计
async getIndexStats(collectionName) {
const collection = this.db.collection(collectionName)
const stats = await collection.aggregate([{ $indexStats: {} }]).toArray()
return stats.map((stat) => ({
name: stat.name,
usageCount: stat.accesses.ops,
lastUsed: stat.accesses.since,
}))
}
// 查找未使用的索引
async findUnusedIndexes(collectionName) {
const stats = await this.getIndexStats(collectionName)
return stats.filter((stat) => stat.name !== '_id_' && stat.usageCount === 0)
}
// 优化建议
async getOptimizationSuggestions(collectionName) {
const collection = this.db.collection(collectionName)
const suggestions = []
// 检查集合统计信息
const collStats = await this.db.command({ collStats: collectionName })
const docCount = collStats.count
const avgDocSize = collStats.avgObjSize
// 建议1: 大集合需要合适的索引
if (docCount > 100000) {
suggestions.push({
type: 'performance',
message: `集合 ${collectionName} 有 ${docCount} 个文档,确保查询字段都有索引`,
})
}
// 建议2: 文档大小过大
if (avgDocSize > 16 * 1024 * 1024 * 0.1) {
// 10% of 16MB
suggestions.push({
type: 'storage',
message: `平均文档大小 ${Math.round(avgDocSize / 1024)}KB,考虑使用引用而非嵌入`,
})
}
// 建议3: 检查未使用的索引
const unusedIndexes = await this.findUnusedIndexes(collectionName)
if (unusedIndexes.length > 0) {
suggestions.push({
type: 'maintenance',
message: `发现 ${unusedIndexes.length} 个未使用的索引,考虑删除以节省存储空间`,
indexes: unusedIndexes.map((idx) => idx.name),
})
}
return suggestions
}
}
2. 查询优化技巧
// 查询优化工具类
class QueryOptimizer {
constructor(db) {
this.db = db
}
// 优化分页查询
async optimizedPagination(collectionName, filter, page, limit, sortField = '_id') {
const collection = this.db.collection(collectionName)
// 使用游标分页而非 skip/limit
if (page === 1) {
return await collection
.find(filter)
.sort({ [sortField]: -1 })
.limit(limit)
.toArray()
} else {
// 获取上一页的最后一个文档的排序字段值
const lastDoc = await this.getLastDocumentFromPreviousPage(
collectionName,
filter,
page - 1,
limit,
sortField
)
if (lastDoc) {
const cursorFilter = {
...filter,
[sortField]: { $lt: lastDoc[sortField] },
}
return await collection
.find(cursorFilter)
.sort({ [sortField]: -1 })
.limit(limit)
.toArray()
}
}
}
// 批量操作优化
async optimizedBulkWrite(collectionName, operations) {
const collection = this.db.collection(collectionName)
const batchSize = 1000
const results = []
for (let i = 0; i < operations.length; i += batchSize) {
const batch = operations.slice(i, i + batchSize)
try {
const result = await collection.bulkWrite(batch, {
ordered: false, // 允许并行执行
writeConcern: { w: 1, j: true }, // 确保写入持久化
})
results.push(result)
} catch (error) {
console.error(`批量操作失败 (批次 ${Math.floor(i / batchSize) + 1}):`, error)
throw error
}
}
return results
}
// 聚合管道优化
optimizeAggregationPipeline(pipeline) {
const optimizedPipeline = [...pipeline]
// 优化1: 将 $match 阶段尽早执行
const matchStages = optimizedPipeline.filter((stage) => stage.$match)
const otherStages = optimizedPipeline.filter((stage) => !stage.$match)
// 优化2: 将 $project 阶段合并
const projectStages = otherStages.filter((stage) => stage.$project)
if (projectStages.length > 1) {
const mergedProject = projectStages.reduce(
(acc, stage) => ({
...acc,
...stage.$project,
}),
{}
)
const nonProjectStages = otherStages.filter((stage) => !stage.$project)
otherStages.splice(0, otherStages.length, ...nonProjectStages, { $project: mergedProject })
}
// 优化3: 使用 $limit 减少处理的文档数量
const limitStage = otherStages.find((stage) => stage.$limit)
if (limitStage) {
const limitIndex = otherStages.indexOf(limitStage)
const beforeLimit = otherStages.slice(0, limitIndex)
const afterLimit = otherStages.slice(limitIndex)
// 将 $limit 尽可能前移
const canMoveLimit = beforeLimit.every(
(stage) => stage.$sort || stage.$match || stage.$project
)
if (canMoveLimit) {
otherStages.splice(limitIndex, 1)
otherStages.splice(beforeLimit.length - 1, 0, limitStage)
}
}
return [...matchStages, ...otherStages]
}
// 查询性能监控
async monitorSlowQueries(thresholdMs = 100) {
// 启用慢查询日志
await this.db.admin().command({
profile: 2,
slowms: thresholdMs,
})
// 获取慢查询
const slowQueries = await this.db
.collection('system.profile')
.find({
ts: { $gte: new Date(Date.now() - 24 * 60 * 60 * 1000) }, // 最近24小时
millis: { $gte: thresholdMs },
})
.sort({ ts: -1 })
.limit(100)
.toArray()
return slowQueries.map((query) => ({
timestamp: query.ts,
duration: query.millis,
namespace: query.ns,
command: query.command,
docsExamined: query.docsExamined,
docsReturned: query.docsReturned,
planSummary: query.planSummary,
}))
}
}
数据建模最佳实践
1. 关系建模策略
// 不同关系类型的建模策略
class DataModelingStrategies {
// 一对一关系 - 嵌入式设计
static oneToOneEmbedded() {
return {
user: {
_id: ObjectId('...'),
username: 'john_doe',
email: 'john@example.com',
profile: {
// 嵌入式一对一
firstName: 'John',
lastName: 'Doe',
bio: 'Software Developer',
avatar: 'https://example.com/avatar.jpg',
socialLinks: {
twitter: '@johndoe',
github: 'johndoe',
linkedin: 'john-doe',
},
},
settings: {
// 嵌入式一对一
theme: 'dark',
language: 'zh-CN',
timezone: 'Asia/Shanghai',
notifications: {
email: true,
push: false,
sms: true,
},
},
},
}
}
// 一对多关系 - 嵌入式设计(适用于"多"的一方数量有限)
static oneToManyEmbedded() {
return {
blogPost: {
_id: ObjectId('...'),
title: 'MongoDB 数据建模',
content: '...',
comments: [
// 嵌入式一对多
{
_id: ObjectId('...'),
author: 'Alice',
content: '很好的文章!',
createdAt: new Date(),
replies: [
{
_id: ObjectId('...'),
author: 'Bob',
content: '我也这么认为',
createdAt: new Date(),
},
],
},
],
},
}
}
// 一对多关系 - 引用设计(适用于"多"的一方数量很大)
static oneToManyReferenced() {
return {
author: {
_id: ObjectId('507f1f77bcf86cd799439011'),
name: 'John Doe',
email: 'john@example.com',
bio: 'Prolific writer',
},
posts: [
{
_id: ObjectId('507f1f77bcf86cd799439012'),
title: 'First Post',
content: '...',
authorId: ObjectId('507f1f77bcf86cd799439011'), // 引用作者
createdAt: new Date(),
},
{
_id: ObjectId('507f1f77bcf86cd799439013'),
title: 'Second Post',
content: '...',
authorId: ObjectId('507f1f77bcf86cd799439011'), // 引用作者
createdAt: new Date(),
},
],
}
}
// 多对多关系 - 数组引用
static manyToManyArrayReferences() {
return {
user: {
_id: ObjectId('507f1f77bcf86cd799439011'),
username: 'john_doe',
followingIds: [
// 关注的用户ID数组
ObjectId('507f1f77bcf86cd799439012'),
ObjectId('507f1f77bcf86cd799439013'),
],
followerIds: [
// 粉丝用户ID数组
ObjectId('507f1f77bcf86cd799439014'),
ObjectId('507f1f77bcf86cd799439015'),
],
},
}
}
// 多对多关系 - 中间集合
static manyToManyJunctionCollection() {
return {
users: [
{
_id: ObjectId('507f1f77bcf86cd799439011'),
username: 'john_doe',
},
{
_id: ObjectId('507f1f77bcf86cd799439012'),
username: 'jane_smith',
},
],
roles: [
{
_id: ObjectId('507f1f77bcf86cd799439021'),
name: 'admin',
permissions: ['read', 'write', 'delete'],
},
{
_id: ObjectId('507f1f77bcf86cd799439022'),
name: 'editor',
permissions: ['read', 'write'],
},
],
userRoles: [
// 中间集合
{
_id: ObjectId('507f1f77bcf86cd799439031'),
userId: ObjectId('507f1f77bcf86cd799439011'),
roleId: ObjectId('507f1f77bcf86cd799439021'),
assignedAt: new Date(),
assignedBy: ObjectId('507f1f77bcf86cd799439012'),
},
],
}
}
}
2. 性能优化模式
// 性能优化设计模式
class PerformancePatterns {
// 模式1: 计算字段模式
static computedFieldPattern() {
return {
// 在写入时计算并存储聚合值
order: {
_id: ObjectId('...'),
items: [
{ productId: ObjectId('...'), price: 100, quantity: 2 },
{ productId: ObjectId('...'), price: 50, quantity: 1 },
],
// 预计算的字段
itemCount: 2,
totalAmount: 250,
averageItemPrice: 125,
createdAt: new Date(),
},
}
}
// 模式2: 桶模式(时间序列数据)
static bucketPattern() {
return {
// 将时间序列数据按时间段分桶存储
temperatureReadings: {
_id: ObjectId('...'),
sensorId: 'sensor_001',
date: new Date('2024-03-10'),
hour: 14, // 14:00-14:59 的数据桶
readings: [
{ minute: 0, temperature: 23.5, humidity: 65 },
{ minute: 1, temperature: 23.6, humidity: 64 },
{ minute: 2, temperature: 23.4, humidity: 66 },
// ... 最多60个读数
],
count: 60,
avgTemperature: 23.5,
minTemperature: 23.1,
maxTemperature: 23.9,
},
}
}
// 模式3: 近似计数模式
static approximateCountingPattern() {
return {
// 使用近似计数避免精确计数的性能开销
post: {
_id: ObjectId('...'),
title: '热门文章',
content: '...',
stats: {
viewCount: 15420, // 精确计数
viewCountApprox: '15K+', // 近似显示
likeCount: 892,
likeCountApprox: '800+',
lastUpdated: new Date(),
},
},
}
}
// 模式4: 预聚合模式
static preAggregationPattern() {
return {
// 原始数据
salesTransaction: {
_id: ObjectId('...'),
productId: ObjectId('...'),
categoryId: ObjectId('...'),
amount: 150,
date: new Date('2024-03-10T10:30:00Z'),
},
// 预聚合的日报表
dailySalesReport: {
_id: ObjectId('...'),
date: new Date('2024-03-10'),
totalSales: 15420,
transactionCount: 156,
averageTransactionAmount: 98.85,
topCategories: [
{ categoryId: ObjectId('...'), sales: 5200, count: 52 },
{ categoryId: ObjectId('...'), sales: 3800, count: 38 },
],
topProducts: [
{ productId: ObjectId('...'), sales: 1200, count: 8 },
{ productId: ObjectId('...'), sales: 980, count: 12 },
],
},
}
}
// 模式5: 版本控制模式
static versioningPattern() {
return {
// 文档版本控制
document: {
_id: ObjectId('...'),
title: '重要文档',
currentVersion: 3,
versions: [
{
version: 1,
content: '初始内容',
author: 'Alice',
createdAt: new Date('2024-03-01T10:00:00Z'),
},
{
version: 2,
content: '修订内容',
author: 'Bob',
createdAt: new Date('2024-03-05T14:30:00Z'),
changes: ['添加了新章节', '修正了错误'],
},
{
version: 3,
content: '最新内容',
author: 'Alice',
createdAt: new Date('2024-03-10T09:15:00Z'),
changes: ['更新了统计数据'],
},
],
},
}
}
}
总结
MongoDB 数据库设计与优化需要考虑多个方面:
- 数据建模:根据查询模式选择嵌入式或引用式设计
- 索引策略:创建合适的索引以支持查询性能
- 查询优化:使用聚合管道和查询优化技巧
- 性能模式:应用计算字段、桶模式等优化模式
- 监控调优:持续监控性能并进行优化
掌握这些技能,你就能设计出高性能、可扩展的 MongoDB 应用!
MongoDB 是现代应用的理想数据库选择,值得深入学习和实践。