MongoDB 适用场景分析

候选人小张在字节 P6 面试中,面试官问:

"你们公司什么场景用了 MongoDB?为什么?"

小张说:"我们用 MongoDB 存日志...因为 MongoDB 是文档数据库。"

面试官追问:"存日志为什么不用 Elasticsearch?"

小张说:"...也可以?"

面试官继续追问:"MongoDB 存日志有什么问题?"

小张答不上来了。

【面试官心理】 这道题我用来测试候选人对 MongoDB 适用场景的理解深度。能说出几个适用场景的占 50%,能讲清选型原因的占 20%,能对比其他方案的占 10%。

一、适合 MongoDB 的场景 🔴

1.1 内容管理系统(CMS)

// 场景:博客、新闻、电商商品等
// 特点:字段变化频繁,嵌套结构多

// 文章文档结构
{
    _id: ObjectId(),
    title: "MongoDB 最佳实践",
    content: "...",
    author: {
        name: "张三",
        bio: "MongoDB 专家",
        social: {
            twitter: "@zhang",
            github: "zhangsan"
        }
    },
    tags: ["MongoDB", "Database"],
    comments: [
        {
            user: "李四",
            text: "好文",
            created_at: ISODate("2024-01-01")
        }
    ],
    related_articles: [
        ObjectId("..."),
        ObjectId("...")
    ]
}

// 为什么适合:
// 1. 字段随时增减,不需要 ALTER TABLE
// 2. 嵌套评论直接存储,减少 JOIN
// 3. 数组字段支持原子操作

1.2 用户画像与行为数据

// 场景:用户标签、行为记录、偏好设置
// 特点:字段不固定,数据量大

// 用户画像文档
{
    _id: ObjectId("user_10001"),
    user_id: 10001,
    profile: {
        age: 25,
        gender: "male",
        location: "Beijing"
    },
    tags: ["tech", "gaming", "music"],
    behavior: {
        page_views: 1500,
        avg_session_time: 300,
        last_active: ISODate("2024-01-15")
    },
    preferences: {
        color: "dark",
        language: "zh-CN"
    },
    // 随时可以添加新字段
    subscription_tier: "premium"
}

// 为什么适合:
// 1. 灵活的数据模型,适应变化
// 2. 高并发写入
// 3. 支持多键索引

1.3 物联网(IoT)数据

// 场景:传感器数据、设备状态、日志
// 特点:时序数据、高写入量

// 设备数据文档
{
    _id: ObjectId(),
    device_id: "sensor_001",
    timestamp: ISODate("2024-01-15T10:30:00Z"),
    type: "temperature",
    value: 25.5,
    unit: "celsius",
    location: {
        building: "A",
        floor: 3,
        room: "301"
    }
}

// 时序集合(MongoDB 5.0+)
db.createCollection("sensor_data", {
    timeseries: {
        timeField: "timestamp",
        metaField: "metadata",
        granularity: "seconds"
    }
})

// 为什么适合:
// 1. 时序数据支持(5.0+)
// 2. 高写入吞吐量
// 3. 按时间范围查询高效

二、不适合 MongoDB 的场景 🟡

2.1 金融交易系统

// ❌ 问题:强一致性要求
// MongoDB 事务比 MySQL 开销大

// 不适合的场景:
// - 账户余额扣减
// - 订单金额计算
// - 库存扣减

// 解决方案:使用 PostgreSQL 或 MySQL

2.2 复杂报表与BI分析

// ❌ 问题:复杂 SQL 支持有限
// MongoDB Aggregation Pipeline 学习曲线陡

// 不适合的场景:
// - 多表关联的大数据分析
// - 窗口函数查询
// - 复杂子查询

// 解决方案:使用 ClickHouse 或 PostgreSQL

2.3 日志存储与分析

// ❌ 问题:不是最优选择
// Elasticsearch 是更好的日志分析方案

// MongoDB 存日志的问题:
// 1. 全文检索能力弱
// 2. 日志聚合分析不如 ES
// 3. 磁盘占用大

// 解决方案:使用 ELK Stack (Elasticsearch + Logstash + Kibana)

三、真实业务场景案例 🟡

3.1 电商订单系统

// MongoDB 适合存订单吗?

// 适合的场景:
// - 订单扩展字段多
// - 订单商品嵌套
// - 高并发写入

// 不适合的场景:
// - 需要强一致性
// - 需要复杂事务
// - 需要多表关联查询

// 混合方案:
// MySQL: 订单主表、支付记录、库存
// MongoDB: 订单详情、商品快照
// MongoDB 订单文档
{
    _id: ObjectId(),
    order_no: "OR202401010001",
    user_id: 10001,
    status: "pending",
    items: [
        {
            product_id: "P001",
            product_name: "iPhone 15",
            sku_id: "SKU001",
            quantity: 1,
            price: 7999.00
        }
    ],
    shipping_address: {
        name: "张三",
        phone: "13800138000",
        address: "北京市朝阳区..."
    },
    // 扩展字段,随时添加
    source: "app",
    coupon_code: "SAVE10"
}

3.2 实时聊天系统

// MongoDB 适合存聊天记录吗?

// ✅ 适合的原因:
// 1. 消息嵌套结构
// 2. 高并发写入
// 3. 支持按时间范围查询
// 4. 副本集保证高可用

// 聊天消息文档
{
    _id: ObjectId(),
    conversation_id: ObjectId("..."),
    sender_id: 10001,
    receiver_id: 10002,
    type: "text",  // text/image/file/audio
    content: "你好",
    attachments: [
        { type: "image", url: "https://..." }
    ],
    status: "sent",  // sent/delivered/read
    created_at: ISODate()
}

// 按会话查询
db.messages.find({
    conversation_id: ObjectId("...")
}).sort({created_at: -1})

3.3 游戏后端数据

// 游戏数据为什么适合 MongoDB?

// 1. 玩家数据灵活
{
    _id: ObjectId(),
    player_id: 10001,
    name: "玩家张三",
    level: 50,
    inventory: {
        gold: 10000,
        gems: 500,
        items: [
            { item_id: "sword", count: 1 }
        ]
    },
    achievements: ["first_blood", "dragon_slayer"],
    // 随时可以加新字段
    vip_level: 3
}

// 2. 排行榜
db.players.createIndex({ score: -1 })
db.players.find().sort({ score: -1 }).limit(100)

// 3. 游戏日志
{
    event: "item_purchase",
    player_id: 10001,
    item_id: "sword",
    timestamp: ISODate()
}

四、选型 Checklist 🟡

4.1 选择 MongoDB 的条件

// ✅ 选择 MongoDB 当:
// 1. 数据结构灵活多变
// 2. 需要频繁添加/删除字段
// 3. 写入量大于查询复杂度
// 4. 需要水平扩展
// 5. 文档天然建模(嵌套结构)
// 6. 需要高可用(副本集)

4.2 不选择 MongoDB 的条件

// ❌ 不选择 MongoDB 当:
// 1. 需要强 ACID 事务
// 2. 需要复杂多表 JOIN
// 3. 需要完整的 SQL 支持
// 4. 数据量小(< 1TB)
// 5. 团队不熟悉 NoSQL
// 6. 需要专业 BI 工具支持

4.3 常见组合方案

场景数据库组合说明
电商平台MySQL + Redis + MongoDBMySQL 订单,Redis 缓存,MongoDB 商品详情
游戏MongoDB + MySQLMongoDB 玩家数据,MySQL 充值记录
社交MongoDB + MySQL + RedisMongoDB 动态,MySQL 用户,Redis Feed
IoTMongoDB + TimescaleDBMongoDB 设备元数据,TimescaleDB 时序数据
💡

MongoDB 不是 MySQL 的替代品,而是补充。选择时要根据具体业务需求,而不是"哪个更流行"。

【面试官心理】 能说出"日志存 Elasticsearch 更合适"和"金融系统不适合 MongoDB"的候选人,基本都有实际的架构经验。这是 P6+ 的水准。