MongoDB

MongoDB 是目前最流行的文档型 NoSQL 数据库,因灵活的 schema、高扩展性和适用于非结构化 / 半结构化数据场景而被广泛使用。以下是关于 MongoDB 的核心知识点及常见面试题:

一、基础概念与特性

  1. 什么是 MongoDB?它的核心特性是什么?

    • 定义:MongoDB 是一个开源的文档型 NoSQL 数据库,数据以类似 JSON 的 "文档"(BSON 格式)存储,无需预定义 schema(表结构),适合存储非结构化或半结构化数据。
    • 核心特性:
      • 文档模型:数据以键值对形式的文档(BSON)存储,支持嵌套结构(如嵌入子文档、数组),更贴近业务对象(如用户文档可直接包含地址、订单列表)。
      • 无 schema 设计:同一集合(Collection)中的文档可拥有不同字段和结构,适合快速迭代的业务(如电商商品属性多变场景)。
      • 高可扩展性:支持副本集(高可用)和分片(水平扩展),轻松应对海量数据和高并发。
      • 丰富的查询能力:支持复杂查询(如范围查询、正则匹配)、聚合管道(数据分析)、地理空间查询等。
      • 索引支持:类似关系型数据库,支持单字段、复合、地理空间等多种索引,提升查询效率。
  2. MongoDB 与关系型数据库(如 MySQL)的核心区别是什么?

    维度 MongoDB(文档型) 关系型数据库(如 MySQL)
    数据模型 文档(BSON),支持嵌套和数组 二维表(行 + 列),需预定义表结构
    Schema 动态 schema(同一集合文档结构可不同) 固定 schema(表结构需提前定义,修改成本高)
    关联关系 推荐通过 "嵌入文档" 减少关联,也支持引用($lookup) 通过外键强关联(JOIN 操作)
    事务支持 4.0+ 支持多文档事务(有限制) 完整 ACID 事务支持
    适用场景 非结构化数据(日志、用户画像)、快速迭代业务 结构化数据(订单、财务)、强事务场景
  3. MongoDB 中的 "文档(Document)""集合(Collection)""数据库(Database)" 分别对应关系型数据库的什么概念?

    • 文档(Document) :类似关系型数据库的 "行(Row)",但结构更灵活(可嵌套),以 BSON(二进制 JSON)格式存储(支持更多数据类型,如日期、ObjectId)。例:一个用户文档

      json

      复制代码
      {
        "_id": ObjectId("650a1b3d7f82e1234567890"),  // 自动生成的唯一标识
        "name": "张三",
        "age": 25,
        "address": { "city": "北京", "street": "XX路" },  // 嵌入子文档
        "hobbies": ["篮球", "游戏"]  // 数组
      }
    • 集合(Collection):类似关系型数据库的 "表(Table)",是文档的集合,但集合中文档的结构可以不同(无 schema 约束)。

    • 数据库(Database) :类似关系型数据库的 "数据库",是集合的容器,一个 MongoDB 实例可包含多个数据库(如 user_dborder_db)。

  4. MongoDB 中的 _id 字段有什么作用?

    • _id 是文档的唯一标识 ,类似关系型数据库的主键(Primary Key),每个文档必须包含 _id 字段(若未手动指定,MongoDB 会自动生成)。
    • 自动生成的 _idObjectId 类型(12 字节),包含时间戳、机器 ID、进程 ID、自增计数器,确保分布式环境下的唯一性。
    • 可手动指定 _id(如用业务 ID 作为 _id),但需保证唯一性,否则插入会报错(duplicate key error)。

二、数据类型与核心操作

  1. **MongoDB 支持哪些特殊数据类型?**除了常见的字符串(String)、数字(Int/Double)、布尔(Boolean),还支持:

    • ObjectId:用于 _id 字段,确保文档唯一性。
    • Date:日期时间(精确到毫秒),如 ISODate("2023-09-20T08:00:00Z")
    • Array:数组,可包含多个值(如 [1, 2, 3]["a", {b:1}])。
    • Embedded Document:嵌入子文档(如 {address: {city: "上海"}})。
    • Binary Data:二进制数据(如图片、文件)。
    • Regular Expression:正则表达式(用于模糊查询)。
  2. MongoDB 的 CRUD 操作常用命令是什么?

    • 创建(Create)insertOne()(单文档)、insertMany()(多文档)

      javascript

      运行

      复制代码
      db.users.insertOne({ name: "李四", age: 30 })  // 插入单条
      db.users.insertMany([{ name: "王五" }, { name: "赵六" }])  // 插入多条
    • 查询(Read)find()(查询所有)、findOne()(查询单条),支持条件筛选(query)和投影(projection

      javascript

      运行

      复制代码
      // 查询年龄>25的用户,只返回name和age字段(_id默认返回,需显式排除)
      db.users.find({ age: { $gt: 25 } }, { name: 1, age: 1, _id: 0 })
    • 更新(Update)updateOne()(更新匹配的第一条)、updateMany()(更新所有匹配),需用更新操作符($set$inc 等)

      javascript

      运行

      复制代码
      // 将name=李四的用户年龄+1
      db.users.updateOne({ name: "李四" }, { $inc: { age: 1 } })
    • 删除(Delete)deleteOne()(删除匹配的第一条)、deleteMany()(删除所有匹配)

      javascript

      运行

      复制代码
      // 删除年龄<18的用户
      db.users.deleteMany({ age: { $lt: 18 } })
  3. MongoDB 常用的查询操作符有哪些?

    • 比较操作符:$eq(等于)、$gt(大于)、$lt(小于)、$gte(大于等于)、$lte(小于等于)、$ne(不等于)、$in(在数组中)、$nin(不在数组中)。例:db.users.find({ age: { $gte: 18, $lte: 30 } })(查询 18-30 岁用户)。
    • 逻辑操作符:$and$or$not。例:db.users.find({ $or: [{ age: { $gt: 30 } }, { name: "张三" }] })
    • 数组操作符:$in(数组包含任一元素)、$all(数组包含所有元素)、$size(数组长度)。例:db.users.find({ hobbies: { $all: ["篮球", "游戏"] } })(爱好同时包含篮球和游戏)。
    • 嵌入文档操作符:$(匹配数组中的元素)、$elemMatch(数组元素多条件匹配)。
  4. 什么是 MongoDB 聚合管道(Aggregation Pipeline)?举例说明其用途。

    • 聚合管道是 MongoDB 用于复杂数据处理和分析的工具,由多个 "阶段(Stage)" 组成,文档按顺序经过每个阶段处理,最终输出结果(类似流水线)。

    • 常用阶段:

      • $match:筛选文档(类似 find 的查询条件)。
      • $group:按字段分组,结合聚合函数($sum$avg 等)。
      • $project:修改文档结构(保留 / 排除字段、重命名)。
      • $sort:排序。
      • $limit:限制返回数量。
    • 示例:统计每个城市的用户数量,并按数量降序排列

      javascript

      运行

      复制代码
      db.users.aggregate([
        { $match: { age: { $gte: 18 } } },  // 先筛选成年用户
        { $group: { _id: "$address.city", count: { $sum: 1 } } },  // 按城市分组计数
        { $sort: { count: -1 } },  // 按数量降序
        { $limit: 10 }  // 取前10
      ])

三、索引与性能优化

  1. **MongoDB 支持哪些类型的索引?**索引用于加速查询,避免全集合扫描(类似关系型数据库),常见类型:

    • 单字段索引 :对单个字段创建索引,如 db.users.createIndex({ name: 1 })(1 为升序,-1 为降序)。
    • 复合索引 :对多个字段创建索引,遵循 "最左前缀原则",如 db.users.createIndex({ age: 1, name: -1 })(查询 ageage+name 可命中,单独查 name 不命中)。
    • 地理空间索引 :用于地理位置查询(如附近的人),如 db.shops.createIndex({ location: "2dsphere" })
    • 文本索引 :用于全文搜索,如 db.articles.createIndex({ content: "text" }),支持 $text 查询。
    • 哈希索引:对字段哈希值创建索引,适合等值查询,不支持范围查询。
  2. 如何查看索引是否被查询使用?如何优化索引?

    • explain() 分析查询执行计划,重点看 executionStats.executionStages 中的 stage 字段:

      • IXSCAN:索引扫描(命中索引,高效);
      • COLLSCAN:全集合扫描(未命中索引,需优化)。例:db.users.find({ age: { $gt: 25 } }).explain("executionStats")
    • 索引优化原则:

      • 只为高频查询字段创建索引(索引会增加写入 / 更新开销)。
      • 复合索引字段顺序:将过滤性强的字段放前面(如性别字段过滤性差,不适合放前面)。
      • 避免过度索引(一个集合索引建议不超过 5-10 个)。
      • 删除未使用的索引(用 db.collection.getIndexes() 查看所有索引,结合监控判断是否有用)。

四、高可用与分布式

  1. 什么是 MongoDB 副本集(Replica Set)?它的作用是什么?

    • 副本集是 MongoDB 实现高可用的核心机制,由多个 MongoDB 实例组成(通常 3 个节点),包含:

      • Primary(主节点):唯一可接收写操作的节点,负责将数据同步到从节点。
      • Secondary(从节点) :从主节点复制数据,仅处理读操作(可通过 readPreference 配置读策略)。
      • Arbiter(仲裁节点):不存储数据,仅在主节点故障时参与投票选举新主节点(减少资源占用)。
    • 作用:

      • 故障转移:主节点宕机后,副本集会自动选举新主节点(通过 Raft 算法),确保服务不中断。
      • 读写分离:读操作可分流到从节点,减轻主节点压力。
      • 数据冗余:数据多副本存储,避免单点故障导致数据丢失。
  2. 副本集的故障转移过程是怎样的?

      1. 检测故障 :从节点定期向主节点发送心跳(默认每 2 秒),若超过 electionTimeoutMillis(默认 10 秒)未收到响应,判定主节点不可用。
      1. 发起选举:一个从节点(优先级高的优先)发起选举,向其他节点请求投票。
      1. 选举新主节点:获得多数节点(超过半数)投票的从节点成为新主节点(如 3 节点副本集需至少 2 票)。
      1. 同步数据:新主节点接收写操作,其他从节点从新主节点同步数据,恢复正常服务。
  3. 什么是 MongoDB 分片(Sharding)?为什么需要分片?

    • 分片是 MongoDB 应对海量数据的水平扩展方案,将大集合的数据拆分到多个 "分片(Shard)"(每个分片是一个副本集),实现数据分布式存储。

    • 为什么需要分片?

      • 单节点存储容量有限(如磁盘空间不足);
      • 单节点读写压力过大(无法通过副本集分担,因副本集数据全量复制)。
    • 分片集群的核心组件:

      • Shard(分片):存储实际数据(每个分片是副本集,保证高可用)。
      • Mongos(路由节点):接收客户端请求,根据分片键将请求路由到对应的分片(客户端只连接 Mongos)。
      • Config Server(配置服务器):存储集群元数据(如分片键范围、分片映射关系),通常为 3 节点副本集。
  4. 分片键(Shard Key)的作用是什么?选择分片键需注意什么?

    • 分片键是用于将集合数据拆分到不同分片的字段(如 user_idcreate_time),MongoDB 通过分片键的值范围或哈希值决定数据存储的分片。

    • 选择原则:

      • 均衡性:分片键需使数据均匀分布到所有分片(避免某分片数据过多,成为瓶颈)。反例:用性别(男 / 女)作为分片键,仅能拆分到 2 个分片,无法扩展。
      • 查询效率:分片键需与高频查询字段匹配(避免 Mongos 向所有分片广播查询)。
      • 不可变:分片键一旦设置,字段值不可修改(否则数据无法正确路由)。

五、事务与数据一致性

  1. MongoDB 支持事务吗?有什么限制?

    • 支持:MongoDB 4.0 开始支持多文档事务(单文档事务天然支持),4.2 后支持分片集群中的事务。
    • 特性:满足 ACID 特性(原子性、一致性、隔离性、持久性),类似关系型数据库事务。
    • 限制:
      • 事务中的写操作会加锁,可能影响性能(建议事务执行时间短)。
      • 分片集群中,事务涉及的文档需在同一个分片(通过分片键保证),否则事务失败。
      • 不支持跨数据库的事务(4.2+ 支持同一部署下的跨库事务)。
  2. 如何保证 MongoDB 数据的一致性?

    • 副本集同步:主节点写入后,数据通过 oplog(操作日志)同步到从节点,确保从节点数据最终一致(默认异步同步,可配置 "多数确认" 保证强一致性)。
    • 事务:多文档操作通过事务保证原子性(要么全成功,要么全失败)。
    • 读写策略:
      • 写操作:通过 writeConcern 配置(如 { w: "majority" } 表示等待多数节点确认后返回,确保数据不丢失)。
      • 读操作:通过 readPreference 配置(如 primary 只从主节点读,保证最新;secondaryPreferred 优先从从节点读,提升性能)。

六、适用场景与局限性

  1. MongoDB 适合哪些场景?不适合哪些场景?
    • 适合场景

      • 非结构化 / 半结构化数据(如日志、用户画像、JSON 格式数据);
      • 快速迭代的业务(无需频繁修改 schema);
      • 高写入吞吐量场景(如物联网设备数据上报);
      • 地理空间查询(如 LBS 应用:附近的商家);
      • 大数据量存储(通过分片扩展)。
    • 不适合场景

      • 强事务需求(如金融交易,虽支持事务,但关系型数据库更成熟);
      • 复杂多表关联查询(MongoDB 的 $lookup 性能不如关系型数据库的 JOIN);
      • 数据一致性要求极高(如库存管理,需频繁锁操作)。
相关推荐
练习时长一年7 小时前
AI开发结构化输出
数据库
IvorySQL7 小时前
灾难恢复工具内核细节探究与分享
数据库·postgresql·开源
lypzcgf7 小时前
商城小程序数据库表结构文档
数据库·小程序·电商
jjw_zyfx8 小时前
Ubuntu上vue3 vite使用MBTiles搭建地图服务器
服务器·数据库·ubuntu
EndingCoder8 小时前
Node.js SQL数据库:MySQL/PostgreSQL集成
javascript·数据库·sql·mysql·postgresql·node.js
静听山水9 小时前
SQLite
数据库·sqlite
草明10 小时前
clickhouse 检查是否有删除语句在执行
数据库·clickhouse
风语者日志10 小时前
攻防世界—easyupload
数据库·web安全·ctf·小白入门
彡皮10 小时前
qt实用学习案例:数据库设计+图表显示+model-view模式+样式表定制
数据库·qt·学习