当前位置: 首页 > news >正文

MongoDB 学习笔记

1. MongoDB 与传统关系型数据库的区别?

MongoDB 是一种 NoSQL 的文档型数据库,和传统关系型数据库(如 MySQL、PostgreSQL)在以下几个方面存在显著差异:

    1. 数据模型
      MongoDB:以 BSON 文档形式存储数据,结构灵活,字段可以嵌套对象和数组,天然适合非结构化或半结构化数据。

关系型数据库:采用表结构,字段和类型固定,严格遵守行与列的二维模型,数据之间通过外键等方式关联。

    1. 模式(Schema)
      MongoDB:默认是 schema-less(无固定模式),可以存储结构不同的文档;也可以通过 JSON Schema 进行约束。

关系型数据库:必须先定义表结构(字段、类型、约束等),插入数据必须符合表定义。

    1. 查询语言
      MongoDB:使用类 JSON 的查询语法,操作方式更接近编程对象操作。

关系型数据库:使用标准的 SQL 语言,具备强大的 JOIN、子查询、事务等能力。

2. MongoDB 的数据模型和基本结构?

MongoDB 是一个基于文档的 NoSQL 数据库,核心的数据模型是「数据库 → 集合 → 文档」的三层结构:

    • 数据库(Database):就像关系型数据库中的一个库。
    • 集合(Collection):类似表,但不需要提前定义字段结构,可以存储结构不同的文档。
    • 文档(Document):是实际存储的数据单元,格式是类 JSON 的 BSON,可以包含嵌套对象和数组。

每个文档默认有一个 _id 主键字段,类型是 ObjectId,也可以自定义。文档中的字段不要求统一,MongoDB 的 schema 是灵活的。

MongoDB 的集合可以隐式创建,也可以使用 db.createCollection() 显式创建;一般情况下是自动创建的,但如果需要添加 schema 验证或者配置固定集合(如 capped collection),就会使用显式方式。

这种模型非常适合处理非结构化、变化频繁的数据,比如内容管理系统、用户行为日志等场景。

3. MongoDB 如何实现主键自增?

MongoDB 默认使用 ObjectId 作为 _id 主键,是全局唯一但不自增。如果需要自增主键,可以在应用层用 Redis ,UUID 或雪花算法生成唯一 ID。

4. MongoDB 如何实现索引?常见索引类型有哪些?

MongoDB 支持多种索引类型,包括单字段、复合索引、唯一索引、文本索引、TTL索引、地理空间索引等。我们可以通过 createIndex() 创建索引,通过 explain() 查看是否命中。使用索引可以大幅提升查询性能,但也会带来写入开销,需要权衡使用。

  • 索引会加快读取,但会增加写入开销(写时需要更新索引);
  • 应避免滥用索引,尤其是重复索引、低选择性字段索引;
  • 查询语句应尽量命中索引前缀(尤其是复合索引);
  • 可通过 explain() 分析查询是否使用了索引;
  • MongoDB 的 _id 字段默认自带唯一索引。

5. MongoDB 如何进行聚合查询?

使用 Spring Data MongoDB 的 Aggregation API

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.stereotype.Service;import java.util.Date;
import java.util.List;@Service
public class SearchHistoryService {@Autowiredprivate MongoTemplate mongoTemplate;public List<UserSearchCount> aggregateSearchCountsLast7Days() {Date sevenDaysAgo = new Date(System.currentTimeMillis() - 7L * 24 * 60 * 60 * 1000);Aggregation aggregation = Aggregation.newAggregation(Aggregation.match(org.springframework.data.mongodb.core.query.Criteria.where("createdAt").gte(sevenDaysAgo)),Aggregation.group("userId").count().as("count"),Aggregation.sort(org.springframework.data.domain.Sort.Direction.DESC, "count"),Aggregation.limit(10));AggregationResults<UserSearchCount> results = mongoTemplate.aggregate(aggregation, "searchHistory", UserSearchCount.class);return results.getMappedResults();}public static class UserSearchCount {private String userId;private int count;// getters and setterspublic String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}}
}

6. MongoDB 是否支持事务?实现机制是什么?

MongoDB 自 4.0 起支持多文档 ACID 事务,基于客户端会话和 WiredTiger 的 MVCC 实现,支持副本集和分片集群环境。分布式事务采用两阶段提交协议,保证跨分片操作的原子性和一致性。事务使用时需启动会话,写操作提交或回滚,性能开销较大,应慎重使用。

7. MongoDB 如何实现高可用?

MongoDB 通过副本集实现高可用,副本集包含主节点和多个从节点,主节点写入数据后同步到从节点;当主节点故障时,自动通过选举产生新的主节点,实现自动故障转移。结合分片集群,可以实现数据的高可用和水平扩展。

8. MongoDB 如何做分片?分片的原理是什么?

MongoDB 分片机制类似 Kafka 的分区概念,都是将数据划分为多个分区(分片),但 MongoDB 的分片是针对 collection 的数据做水平切分,每个分片本身是一个副本集,保证高可用。客户端通过 mongos 路由器把请求按 shard key 路由到对应分片,实现分布式存储和负载均衡。

方面

MongoDB 分片(Sharding)

Kafka 分区(Partition)

划分粒度

一个数据库中的每个 collection 可以分成多个分片

一个 topic 可以划分成多个分区

分片含义

分片是数据水平切分,分片内存储部分数据

分区是消息队列的基本单位,每个分区存储部分消息

副本机制

每个分片本身是一个副本集,分片有主节点和多个从节点

分区有一个 leader(主节点)和多个 follower(副本)

数据分布方式

根据 shard key(分片键)决定数据路由到哪个分片

生产者根据 key 决定消息写入哪个分区

扩展性

通过增加分片节点实现水平扩展,分片数目固定不轻易变动

分区数在 topic 创建时定义,运行中不易变

主要目的

解决数据量大、读写压力高的问题,实现大规模分布式存储

实现高吞吐、高可用的消息传递

9. MongoDB 性能优化常见措施有哪些?

1.合理设计索引

建立常用查询字段的索引,避免全表扫描

利用复合索引覆盖多个查询条件

使用唯一索引保证数据唯一性和快速定位

避免索引过多,防止写入性能下降

利用TTL 索引自动过期数据,减小数据量

2.集群与硬件层面优化

使用副本集实现读写分离,读取从节点,减轻主节点压力

合理配置分片集群,实现水平扩展和负载均衡

3.优化查询

避免使用不支持索引的查询操作,如正则表达式前缀不确定的查询

使用 explain() 分析查询执行计划,发现慢查询

避免在大文档里返回不必要的字段,使用 投影(projection)减少数据传输

合理分页,避免大偏移量分页带来的性能损耗,推荐基于条件的“游标”分页

10. MongoDB 和 Elasticsearch 如何配合使用?

MongoDB 负责存储,Elasticsearch 负责搜索,通过同步机制保持数据一致,实现高性能、高可用的搜索架构。

典型流程示例:

用户发起搜索请求

前端将搜索关键词发送到后端。

ES 执行全文检索

后端调用 ES,快速定位相关文档(例如文章、商品等),并返回匹配结果。

MongoDB 记录搜索历史

将用户搜索关键词、时间戳、用户ID 等信息异步写入 MongoDB,方便后续做热搜、个性化推荐等。

MySQL 作为主数据源

存储业务核心数据,如用户信息、订单、权限等,确保数据完整性和事务一致。

方式 1:应用层双写(同步写入)

  • 代码中同时写入 MongoDB 和 Elasticsearch。
  • 优点:实现简单。
  • 缺点:耦合高、失败处理复杂。
articleRepository.save(article);     // MongoDB
esClient.index(articleDoc);         // Elasticsearch

方式 2:异步同步(推荐)

  • 写入 MongoDB 后发送事件(Kafka、RabbitMQ、RocketMQ)
  • 消费者异步同步数据到 Elasticsearch。
  • 优点:解耦、性能好、可靠性强。
用户发请求 → MongoDB 存数据 → 发送同步事件 → 消费者写入 Elasticsearch

11. 搜索框的历史搜索记录,用 MongoDB 存储有什么好处?

1. MongoDB 支持灵活字段、嵌套对象和数组,无需修改表结构即可扩展字段,开发迭代效率高。

2. MongoDB 的写入性能优于传统关系型数据库,特别适合高并发、高速写入场景。搜索记录属于典型的“写多读少。

3. MongoDB 支持 TTL 索引,可以自动删除过期数据,免维护清理脚本

db.searchHistory.createIndex({ createdAt: 1 },                    // 对 createdAt 字段创建升序索引{ expireAfterSeconds: 2592000 }      // 设置文档在 createdAt 时间点后 2592000 秒自动过期(30 天)
)

12. 如何在项目中使用 MongoDB?

1. 添加依赖(Maven)

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

2. 配置 application.properties

spring.data.mongodb.uri=mongodb://localhost:27017/mydb

3. 定义实体类

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;@Document(collection = "users")
public class User {@Idprivate String id;private String name;private Integer age;// getters and setters
}

4. 定义 Repository 接口

import org.springframework.data.mongodb.repository.MongoRepository;public interface UserRepository extends MongoRepository<User, String> {User findByName(String name);
}

5. 使用示例

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate UserRepository userRepository;public void runExample() {User user = new User();user.setName("Alice");user.setAge(25);userRepository.save(user);User found = userRepository.findByName("Alice");System.out.println(found.getName() + ", " + found.getAge());}
}

http://www.lryc.cn/news/589443.html

相关文章:

  • 三年高端随身WIFI销量冠军如何用“技术普惠”击穿行业暴利,用户直呼真香;随身WIFI哪个牌子性价比最高?
  • netstat -tlnp | grep 5000
  • 基于Python的图像文字识别系统
  • Linux探秘坊-------14.信号
  • ObservableValidator自定义错误样式
  • 从知识变现到创始人IP:知识付费的进阶之路
  • zip 加密压缩文件的原理是什么?
  • 【Java】【企业级应用】学生信息管理系统项目介绍
  • 算法入门:BFS与DFS详解(C++实现)
  • 【kubernetes】--ConfigMap
  • 极致cms多语言建站|设置主站默认语言与设置后台固定语言为中文
  • frp内网穿透(二)
  • 牛客:HJ20 密码验证合格程序[华为机考][字符串]
  • 一般芯片电气特性中Flash参数达到其最大值的条件是什么?
  • 【人工智能99问】激活函数有哪些,如何选择使用哪个激活函数?(5/99)
  • 全新 Python 项目托管到 Gitee 私有仓库完整流程(带详细命令注释)
  • 【PTA数据结构 | C语言版】构造二叉树
  • 软件质量概述
  • 使用 pdb 来 debug 调试 python 程序
  • I3C通信驱动开发注意事项
  • Linux715 磁盘管理:逻辑卷
  • golang二级缓存示例
  • 随机奖励能提升Qwen数学表现?本质是数据污染
  • NuGet01-安装及使用
  • Linux下编译海思WS63 SDK全攻略
  • 关于Linux下Cursor的使用
  • 如何设计实现开发自助重启工具-01-设计篇
  • 代码随想录八股文训练营总结
  • lesson14:Python的推导式
  • 2025-07-15 李沐深度学习6——Softmax回归