MongoDB 完整指南

MongoDB 完整指南

目录

MongoDB简介

什么是MongoDB

MongoDB是一个基于分布式文件存储的NoSQL数据库,由C++语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案。

主要特点

  • 文档导向: 数据以BSON(Binary JSON)格式存储
  • 高性能: 支持索引、聚合、分片等特性
  • 高可用性: 支持复制集和自动故障转移
  • 水平扩展: 支持分片集群,可横向扩展
  • 灵活模式: 无需预定义表结构,支持动态字段

适用场景

  • 大数据量、高并发的Web应用
  • 内容管理系统
  • 实时分析系统
  • 物联网数据存储
  • 日志系统

核心概念

数据库结构

复制代码
MongoDB实例
├── 数据库(Database)
│   ├── 集合(Collection) - 相当于关系数据库中的表
│   │   ├── 文档(Document) - 相当于关系数据库中的行
│   │   │   ├── 字段(Field) - 相当于关系数据库中的列
│   │   │   └── 值(Value)
│   │   └── 索引(Index)
│   └── 用户(User)
└── 配置(Configuration)

数据类型

  • 基本类型: String, Number, Boolean, Date, ObjectId
  • 复合类型: Array, Object, Null
  • 特殊类型: Binary Data, Regular Expression, Timestamp

使用技巧

1. 索引优化

javascript 复制代码
// 创建单字段索引
db.collection.createIndex({ "field": 1 })

// 创建复合索引
db.collection.createIndex({ "field1": 1, "field2": -1 })

// 创建文本索引
db.collection.createIndex({ "content": "text" })

// 创建地理空间索引
db.collection.createIndex({ "location": "2dsphere" })

2. 聚合管道

javascript 复制代码
// 复杂聚合查询示例
db.orders.aggregate([
  { $match: { status: "completed" } },
  { $group: { 
    _id: "$customerId", 
    totalAmount: { $sum: "$amount" },
    orderCount: { $sum: 1 }
  }},
  { $sort: { totalAmount: -1 } },
  { $limit: 10 }
])

3. 批量操作

javascript 复制代码
// 批量插入
db.collection.bulkWrite([
  { insertOne: { document: { name: "John", age: 30 } } },
  { insertOne: { document: { name: "Jane", age: 25 } } },
  { updateOne: { filter: { name: "John" }, update: { $set: { age: 31 } } } }
])

4. 数据验证

javascript 复制代码
// 创建集合时定义验证规则
db.createCollection("users", {
  validator: {
    $jsonSchema: {
      required: ["name", "email"],
      properties: {
        name: { type: "string", minLength: 2 },
        email: { type: "string", pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" },
        age: { type: "number", minimum: 0, maximum: 150 }
      }
    }
  }
})

重难点解析

1. 事务处理

javascript 复制代码
// MongoDB 4.0+ 支持多文档事务
const session = db.getMongo().startSession();
session.startTransaction();

try {
  // 执行多个操作
  db.accounts.updateOne(
    { _id: "account1" },
    { $inc: { balance: -100 } },
    { session }
  );
  
  db.accounts.updateOne(
    { _id: "account2" },
    { $inc: { balance: 100 } },
    { session }
  );
  
  session.commitTransaction();
} catch (error) {
  session.abortTransaction();
  throw error;
} finally {
  session.endSession();
}

2. 分片策略

javascript 复制代码
// 启用分片
sh.enableSharding("database")

// 对集合进行分片
sh.shardCollection("database.collection", { "shardKey": 1 })

// 分片键选择原则
// - 基数高(唯一值多)
// - 写分布均匀
// - 支持单调递增

3. 复制集配置

javascript 复制代码
// 复制集配置示例
config = {
  _id: "rs0",
  members: [
    { _id: 0, host: "mongodb0.example.net:27017" },
    { _id: 1, host: "mongodb1.example.net:27017" },
    { _id: 2, host: "mongodb2.example.net:27017" }
  ]
}

rs.initiate(config)

4. 性能优化

javascript 复制代码
// 使用投影减少数据传输
db.collection.find({}, { name: 1, email: 1, _id: 0 })

// 使用hint强制使用特定索引
db.collection.find({ field: "value" }).hint({ field: 1 })

// 使用explain分析查询性能
db.collection.find({ field: "value" }).explain("executionStats")

Spring Boot集成

1. 依赖配置

xml 复制代码
<!-- Maven -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
gradle 复制代码
// Gradle
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'

2. 配置文件

yaml 复制代码
# application.yml
spring:
  data:
    mongodb:
      host: localhost
      port: 27017
      database: mydb
      username: admin
      password: password
      authentication-database: admin
    
      # 连接池配置
      max-connection-pool-size: 100
      min-connection-pool-size: 5
      max-connection-idle-time: 30000
    
      # 复制集配置
      # uri: mongodb://user:pass@host1:port1,host2:port2/database?replicaSet=rs0

3. 实体类定义

java 复制代码
@Document(collection = "users")
public class User {
    @Id
    private String id;
  
    @Indexed(unique = true)
    private String email;
  
    private String name;
    private int age;
  
    @CreatedDate
    private LocalDateTime createdAt;
  
    @LastModifiedDate
    private LocalDateTime updatedAt;
  
    // 构造函数、getter、setter
}

4. Repository接口

java 复制代码
@Repository
public interface UserRepository extends MongoRepository<User, String> {
  
    // 自定义查询方法
    List<User> findByName(String name);
  
    List<User> findByAgeGreaterThan(int age);
  
    @Query("{ 'age' : { $gte : ?0, $lte : ?1 } }")
    List<User> findByAgeBetween(int minAge, int maxAge);
  
    // 使用正则表达式
    List<User> findByNameRegex(String regex);
  
    // 分页查询
    Page<User> findByAge(int age, Pageable pageable);
}

5. 服务层实现

java 复制代码
@Service
public class UserService {
  
    @Autowired
    private UserRepository userRepository;
  
    @Autowired
    private MongoTemplate mongoTemplate;
  
    // 基本CRUD操作
    public User createUser(User user) {
        return userRepository.save(user);
    }
  
    public User findById(String id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException("User not found"));
    }
  
    // 使用MongoTemplate进行复杂查询
    public List<User> findUsersByComplexCriteria(String name, int minAge, String city) {
        Criteria criteria = new Criteria();
      
        if (name != null) {
            criteria = criteria.and("name").regex(name, "i");
        }
      
        if (minAge > 0) {
            criteria = criteria.and("age").gte(minAge);
        }
      
        if (city != null) {
            criteria = criteria.and("address.city").is(city);
        }
      
        Query query = new Query(criteria);
        return mongoTemplate.find(query, User.class);
    }
  
    // 聚合查询
    public List<AgeGroup> getUsersByAgeGroup() {
        Aggregation aggregation = Aggregation.newAggregation(
            Aggregation.group("age")
                .count().as("count")
                .avg("age").as("averageAge"),
            Aggregation.sort(Sort.Direction.ASC, "_id")
        );
      
        return mongoTemplate.aggregate(aggregation, "users", AgeGroup.class)
            .getMappedResults();
    }
  
    // 批量操作
    @Transactional
    public void updateUsersAge(String name, int newAge) {
        Query query = new Query(Criteria.where("name").is(name));
        Update update = new Update().set("age", newAge);
        mongoTemplate.updateMulti(query, update, User.class);
    }
}

6. 控制器层

java 复制代码
@RestController
@RequestMapping("/api/users")
public class UserController {
  
    @Autowired
    private UserService userService;
  
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User createdUser = userService.createUser(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
    }
  
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable String id) {
        User user = userService.findById(id);
        return ResponseEntity.ok(user);
    }
  
    @GetMapping("/search")
    public ResponseEntity<List<User>> searchUsers(
            @RequestParam(required = false) String name,
            @RequestParam(required = false) Integer minAge,
            @RequestParam(required = false) String city) {
      
        List<User> users = userService.findUsersByComplexCriteria(name, minAge, city);
        return ResponseEntity.ok(users);
    }
  
    @GetMapping("/age-groups")
    public ResponseEntity<List<AgeGroup>> getAgeGroups() {
        List<AgeGroup> ageGroups = userService.getUsersByAgeGroup();
        return ResponseEntity.ok(ageGroups);
    }
}

7. 配置类

java 复制代码
@Configuration
@EnableMongoRepositories(basePackages = "com.example.repository")
public class MongoConfig extends AbstractMongoClientConfiguration {
  
    @Value("${spring.data.mongodb.database}")
    private String databaseName;
  
    @Override
    protected String getDatabaseName() {
        return databaseName;
    }
  
    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(mongoClient(), getDatabaseName());
    }
  
    // 自定义转换器
    @Bean
    public MongoCustomConversions customConversions() {
        List<Converter<?, ?>> converters = new ArrayList<>();
        converters.add(new LocalDateTimeToDateConverter());
        converters.add(new DateToLocalDateTimeConverter());
        return new MongoCustomConversions(converters);
    }
}

最佳实践

1. 数据建模

  • 嵌入文档: 适合一对少关系,数据不经常变化
  • 引用文档: 适合一对多关系,数据经常变化
  • 混合模式: 根据查询模式选择最优方案

2. 索引策略

  • 为常用查询字段创建索引
  • 避免过多索引(影响写入性能)
  • 使用复合索引优化多字段查询
  • 定期分析索引使用情况

3. 性能优化

  • 使用投影减少数据传输
  • 合理使用分页查询
  • 避免深度嵌套查询
  • 使用聚合管道替代应用层处理

4. 安全配置

  • 启用身份验证
  • 使用TLS/SSL加密
  • 限制网络访问
  • 定期备份数据

5. 监控和维护

  • 监控连接数和性能指标
  • 定期清理无用索引
  • 监控磁盘空间使用
  • 设置告警机制

总结

MongoDB作为NoSQL数据库的代表,具有灵活的数据模型、高性能和良好的扩展性。通过合理的数据建模、索引优化和Spring Boot集成,可以构建高效、可扩展的应用程序。

关键要点:

  1. 理解MongoDB的文档模型和查询语言
  2. 掌握索引和聚合管道的使用
  3. 合理设计数据模型和查询策略
  4. 正确配置Spring Boot集成
  5. 遵循最佳实践确保性能和安全性

通过本指南的学习,您应该能够熟练使用MongoDB并成功集成到Spring Boot项目中。