找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1863

积分

0

好友

263

主题
发表于 昨天 08:34 | 查看: 6| 回复: 0

在互联网项目开发中,面对海量非结构化或半结构化数据(如用户行为日志、商品评论、地理位置信息),传统关系型数据库的固定表结构往往显得捉襟见肘。而 MongoDB 作为主流的文档型 NoSQL 数据库,凭借其 Schema 灵活、高可扩展、原生支持分布式的特性,已成为处理这类数据的首选方案。本文将从实战角度出发,为你完整演示 MongoDB 的安装配置、Spring Boot 集成、核心 CRUD 操作,以及高频实用的聚合查询与地理空间查询,帮你快速落地文档数据库解决方案!本文中涉及的技术资源与讨论,也可以在 云栈社区 找到更多。

一、实战场景与技术选型

1. 业务场景说明

本次实战围绕“电商平台用户行为分析与商品评论管理”展开,核心数据特点如下:

  • 用户行为日志:非结构化,字段灵活(例如浏览、点击、下单等不同行为的字段差异很大)。
  • 商品评论:半结构化,包含用户信息、评论内容、评分、时间、地理位置等多维度数据。
  • 核心需求:需要支持灵活的数据插入、复杂条件查询、评论统计分析(例如按评分分组统计),以及附近用户评论查询(地理空间检索)。

2. 技术选型

  • 文档数据库:MongoDB 6.x(稳定版,支持聚合管道、地理空间索引等核心特性)。
  • 开发框架Spring Boot 2.7.x(简化项目配置和开发)。
  • 数据访问层:Spring Data MongoDB(它极大地简化了 MongoDB 操作,并提供了强大的 Repository 接口)。
  • 其他工具:Lombok(简化代码)、FastJSON(JSON 处理)。

二、前置准备:MongoDB安装与核心配置

1. MongoDB安装(Windows/Linux通用)

(1)下载与安装

  • 官网下载:访问 MongoDB 官网,选择对应操作系统的 6.x 社区版。
  • Windows安装:双击安装包,选择“Complete”完整安装,可以勾选“Install MongoDB Compass”(官方可视化工具,可选)。
  • Linux安装:以 CentOS 为例,可以通过 yum 安装。
    1. 配置 MongoDB yum 源。
    2. 执行 yum install -y mongodb-org
    3. 启动服务:systemctl start mongod;设置开机自启:systemctl enable mongod

(2)验证安装

  • 命令行验证:执行 mongomongosh(MongoDB 6.x 推荐),进入 MongoDB 交互终端,若显示 mongodb> 则安装成功。
  • 基础命令测试
    • 查看数据库列表:show dbs
    • 创建/切换数据库:use ecommerce_db(切换到 ecommerce_db 数据库,不存在则自动创建)。
    • 创建集合:db.createCollection(“user_behavior”)(创建用户行为日志集合)。

2. MongoDB核心配置(优化性能与安全)

MongoDB 默认配置文件路径:

  • WindowsC:\Program Files\MongoDB\Server\6.0\bin\mongod.cfg
  • Linux/etc/mongod.conf

(1)核心配置优化

# 存储配置
storage:
  dbPath: /var/lib/mongo  # 数据存储目录(Linux),Windows默认C:\data\db
  journal:
    enabled: true  # 开启日志持久化,防止数据丢失
  wiredTiger:  # 存储引擎(默认WiredTiger,高性能支持并发)
    engineConfig:
      cacheSizeGB: 2  # 缓存大小(建议设为物理内存的50%)

# 网络配置
net:
  port: 27017  # 默认端口
  bindIp: 0.0.0.0  # 允许所有IP访问(生产环境建议指定具体IP)

# 安全配置(生产环境必开)
security:
  authorization: enabled  # 开启身份认证

# 日志配置
systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log  # 日志路径
  logAppend: true  # 日志追加模式

(2)创建管理员用户与数据库用户

开启身份认证后,必须创建用户才能访问,步骤如下:

  1. 暂时关闭身份认证,启动 MongoDB。
  2. 进入交互终端,创建管理员用户:
    use admin
    db.createUser({
      user: “admin”,
      pwd: “admin123”,
      roles: [{ role: “root”, db: “admin” }]  // 超级管理员权限
    })
  3. 开启身份认证,重启 MongoDB。
  4. 使用管理员账号登录,创建业务数据库用户(例如 ecommerce_db):
    mongosh -u admin -p admin123 --authenticationDatabase admin
    use ecommerce_db
    db.createUser({
      user: “ecommerce_user”,
      pwd: “ecommerce123”,
      roles: [{ role: “readWrite”, db: “ecommerce_db” }]  // 读写权限
    })

3. MongoDB可视化工具使用(MongoDB Compass)

MongoDB Compass 是官方提供的可视化工具,便于数据查看和操作:

  • 连接数据库:输入主机、端口、认证数据库、用户名和密码,点击“Connect”。
  • 核心功能:可以直观地查看集合数据、执行查询语句、创建索引、导出数据等,非常适合开发和调试阶段使用。

三、Spring Boot集成Spring Data MongoDB

Spring Data MongoDB 提供了一套高度简化的 API,支持 Repository 接口、注解式查询等功能,能大幅降低 MongoDB 操作的成本。

1. 核心依赖引入

pom.xml 中添加 Spring Boot Web、Spring Data MongoDB、Lombok 等依赖:

<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Spring Data MongoDB -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

2. 基础配置(application.yml)

配置 MongoDB 连接信息、连接池优化等参数:

spring:
  data:
    mongodb:
      uri: mongodb://ecommerce_user:ecommerce123@127.0.0.1:27017/ecommerce_db?authSource=ecommerce_db
      # 可选:分参数配置(与uri二选一)
      # host: 127.0.0.1
      # port: 27017
      # database: ecommerce_db
      # username: ecommerce_user
      # password: ecommerce123
      # authentication-database: ecommerce_db
    # 连接池优化(Spring Data MongoDB默认使用MongoDB Java Driver的连接池)
    mongodb:
      driver:
        core:
          connection-pool:
            max-size: 100  # 最大连接数
            min-size: 10   # 最小空闲连接数
            max-wait-time: 3000ms  # 最大等待时间
            max-connection-life-time: 3600000ms  # 连接最大生命周期

# 日志配置(开发环境打印MongoDB操作日志)
logging:
  level:
    org.springframework.data.mongodb.core: DEBUG

3. 核心概念与实体类映射

MongoDB 的核心概念与关系型数据库的对应关系如下:

  • 数据库(Database):对应关系型数据库的数据库。
  • 集合(Collection):对应关系型数据库的表。
  • 文档(Document):对应关系型数据库的行。
  • 字段(Field):对应关系型数据库的列。
  • 索引(Index):与关系型数据库索引功能一致,用于提升查询性能。

(1)实体类注解说明

Spring Data MongoDB 通过注解实现实体类与 MongoDB 文档的映射,这些注解的详细用法是学习 Spring Data MongoDB 官方文档 的重要部分:

  • @Document(collection = “集合名”):指定实体类对应 MongoDB 的集合。
  • @Id:指定文档的主键(_id 字段)。
  • @Field(name = “字段名”):指定实体类字段与文档字段的映射关系(可自定义文档字段名)。
  • @Indexed:为该字段创建索引。
  • @Transient:忽略该字段,不存入 MongoDB。
  • @DateTimeFormat:日期时间格式化。

(2)实体类定义(用户行为日志、商品评论)

package com.example.mongodb.entity;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

import java.time.LocalDateTime;
import java.util.Map;

/**
 * 用户行为日志实体(非结构化数据示例)
 */
@Data
@Document(collection = “user_behavior”)  // 对应MongoDB的user_behavior集合
public class UserBehavior {
    @Id  // 主键(MongoDB自动生成ObjectId)
    private String id;

    @Indexed  // 为userId创建索引,提升查询性能
    @Field(name = “user_id”)  // 文档字段名:user_id
    private Long userId;

    @Field(name = “behavior_type”)  // 行为类型:browse(浏览)、click(点击)、order(下单)
    private String behaviorType;

    @Field(name = “goods_id”)  // 关联商品ID
    private Long goodsId;

    @Field(name = “behavior_time”)  // 行为时间
    private LocalDateTime behaviorTime;

    @Field(name = “ext_info”)  // 扩展信息(灵活存储不同行为的额外字段)
    private Map<String, Object> extInfo;  // 非结构化字段,存储动态数据
}

/**
 * 商品评论实体(半结构化数据示例,包含地理空间信息)
 */
@Data
@Document(collection = “goods_comment”)
public class GoodsComment {
    @Id
    private String id;

    @Field(name = “goods_id”)
    @Indexed
    private Long goodsId;

    @Field(name = “user_id”)
    private Long userId;

    @Field(name = “user_name”)
    private String userName;

    @Field(name = “content”)  // 评论内容
    private String content;

    @Field(name = “score”)  // 评分(1-5)
    @Indexed
    private Integer score;

    @Field(name = “comment_time”)
    private LocalDateTime commentTime;

    @Field(name = “location”)  // 地理空间信息(经纬度)
    private GeoPoint location;  // 自定义地理坐标类
}

/**
 * 地理坐标类(适配MongoDB的GeoJSON格式)
 */
@Data
public class GeoPoint {
    @Field(name = “type”)
    private String type = “Point”;  // 类型:点

    @Field(name = “coordinates”)  // 经纬度:[经度, 纬度]
    private double[] coordinates;  // 示例:new double[]{120.12, 30.33}
}

4. Repository接口实现(简化CRUD)

Spring Data MongoDB 提供了 MongoRepository 接口,继承后即可获得默认的 CRUD 方法,无需手动编写代码。

(1)UserBehaviorRepository

package com.example.mongodb.repository;

import com.example.mongodb.entity.UserBehavior;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 用户行为日志Repository(继承MongoRepository)
 */
public interface UserBehaviorRepository extends MongoRepository<UserBehavior, String> {
    // 1. 按方法名自动生成查询(Spring Data MongoDB自动解析方法名)
    // 功能:查询指定用户、指定行为类型的行为日志,按时间倒序
    List<UserBehavior> findByUserIdAndBehaviorTypeOrderByBehaviorTimeDesc(Long userId, String behaviorType);

    // 2. 按时间范围查询
    List<UserBehavior> findByBehaviorTimeBetween(LocalDateTime start, LocalDateTime end);

    // 3. 自定义查询(使用@Query注解,编写MongoDB查询语句)
    // 功能:查询指定商品的浏览行为,只返回userId和behaviorTime字段
    @Query(value = “{ ‘goods_id’ : ?0, ‘behavior_type’ : ‘browse’ }”, fields = “{ ‘user_id’ : 1, ‘behavior_time’ : 1 }”)
    List<UserBehavior> findBrowseBehaviorByGoodsId(Long goodsId);
}

(2)GoodsCommentRepository

package com.example.mongodb.repository;

import com.example.mongodb.entity.GoodsComment;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;

import java.util.List;

/**
 * 商品评论Repository
 */
public interface GoodsCommentRepository extends MongoRepository<GoodsComment, String> {
    // 按商品ID查询评论,按时间倒序
    List<GoodsComment> findByGoodsIdOrderByCommentTimeDesc(Long goodsId);

    // 按评分查询指定商品的评论
    List<GoodsComment> findByGoodsIdAndScore(Long goodsId, Integer score);

    // 自定义查询:查询评分大于等于指定分数的评论
    @Query(value = “{ ‘goods_id’ : ?0, ‘score’ : { $gte : ?1 } }”)
    List<GoodsComment> findHighScoreCommentByGoodsId(Long goodsId, Integer minScore);
}

5. Service层实现(业务逻辑封装)

封装 Repository 接口,实现核心业务逻辑:

package com.example.mongodb.service;

import com.example.mongodb.entity.UserBehavior;
import com.example.mongodb.entity.GoodsComment;
import com.example.mongodb.repository.UserBehaviorRepository;
import com.example.mongodb.repository.GoodsCommentRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Service
@RequiredArgsConstructor
public class MongoDbService {
    private final UserBehaviorRepository userBehaviorRepository;
    private final GoodsCommentRepository goodsCommentRepository;

    // ——————- 用户行为日志相关 ——————-
    // 新增用户行为日志
    public UserBehavior saveUserBehavior(UserBehavior userBehavior) {
        userBehavior.setBehaviorTime(LocalDateTime.now());  // 自动填充时间
        return userBehaviorRepository.save(userBehavior);
    }

    // 分页查询用户行为日志
    public Page<UserBehavior> getUserBehaviorByPage(Long userId, int pageNum, int pageSize) {
        // 按时间倒序排序
        Sort sort = Sort.by(Sort.Direction.DESC, “behaviorTime”);
        Pageable pageable = PageRequest.of(pageNum – 1, pageSize, sort);
        return userBehaviorRepository.findByUserId(userId, pageable);
    }

    // 查询指定商品的浏览行为
    public List<UserBehavior> getBrowseBehaviorByGoodsId(Long goodsId) {
        return userBehaviorRepository.findBrowseBehaviorByGoodsId(goodsId);
    }

    // ——————- 商品评论相关 ——————-
    // 新增商品评论
    public GoodsComment saveGoodsComment(GoodsComment goodsComment) {
        goodsComment.setCommentTime(LocalDateTime.now());
        return goodsCommentRepository.save(goodsComment);
    }

    // 分页查询商品评论
    public Page<GoodsComment> getGoodsCommentByPage(Long goodsId, int pageNum, int pageSize) {
        Sort sort = Sort.by(Sort.Direction.DESC, “commentTime”);
        Pageable pageable = PageRequest.of(pageNum – 1, pageSize, sort);
        return goodsCommentRepository.findByGoodsId(goodsId, pageable);
    }

    // 查询指定商品的高分评论(>=4分)
    public List<GoodsComment> getHighScoreComment(Long goodsId) {
        return goodsCommentRepository.findHighScoreCommentByGoodsId(goodsId, 4);
    }
}

6. Controller层实现(提供API接口)

package com.example.mongodb.controller;

import com.example.mongodb.entity.UserBehavior;
import com.example.mongodb.entity.GoodsComment;
import com.example.mongodb.service.MongoDbService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping(“/api/mongodb”)
@RequiredArgsConstructor
public class MongoDbController {
    private final MongoDbService mongoDbService;

    // ——————- 用户行为日志接口 ——————-
    @PostMapping(“/behavior”)
    public ResponseEntity<UserBehavior> saveUserBehavior(@RequestBody UserBehavior userBehavior) {
        UserBehavior saved = mongoDbService.saveUserBehavior(userBehavior);
        return ResponseEntity.ok(saved);
    }

    @GetMapping(“/behavior/user/{userId}”)
    public ResponseEntity<Page<UserBehavior>> getUserBehavior(
            @PathVariable Long userId,
            @RequestParam(defaultValue = “1”) int pageNum,
            @RequestParam(defaultValue = “10”) int pageSize) {
        Page<UserBehavior> page = mongoDbService.getUserBehaviorByPage(userId, pageNum, pageSize);
        return ResponseEntity.ok(page);
    }

    @GetMapping(“/behavior/goods/{goodsId}/browse”)
    public ResponseEntity<List<UserBehavior>> getBrowseBehavior(@PathVariable Long goodsId) {
        List<UserBehavior> list = mongoDbService.getBrowseBehaviorByGoodsId(goodsId);
        return ResponseEntity.ok(list);
    }

    // ——————- 商品评论接口 ——————-
    @PostMapping(“/comment”)
    public ResponseEntity<GoodsComment> saveGoodsComment(@RequestBody GoodsComment goodsComment) {
        GoodsComment saved = mongoDbService.saveGoodsComment(goodsComment);
        return ResponseEntity.ok(saved);
    }

    @GetMapping(“/comment/goods/{goodsId}”)
    public ResponseEntity<Page<GoodsComment>> getGoodsComment(
            @PathVariable Long goodsId,
            @RequestParam(defaultValue = “1”) int pageNum,
            @RequestParam(defaultValue = “10”) int pageSize) {
        Page<GoodsComment> page = mongoDbService.getGoodsCommentByPage(goodsId, pageNum, pageSize);
        return ResponseEntity.ok(page);
    }

    @GetMapping(“/comment/goods/{goodsId}/high-score”)
    public ResponseEntity<List<GoodsComment>> getHighScoreComment(@PathVariable Long goodsId) {
        List<GoodsComment> list = mongoDbService.getHighScoreComment(goodsId);
        return ResponseEntity.ok(list);
    }
}

四、高级查询:聚合查询与地理空间查询

MongoDB 的强大之处在于其原生支持复杂的聚合查询和地理空间查询,这使其特别适合数据分析和位置相关的业务场景。

1. 聚合查询(Aggregation)

聚合查询用于对集合数据进行多阶段的统计分析(如分组、筛选、排序、计算)。Spring Data MongoDB 通过 Aggregation 类封装了聚合管道操作。

(1)聚合查询场景1:用户行为统计(按行为类型分组计数)

需求:统计指定用户的各类行为数量(如浏览、点击、下单次数)。

package com.example.mongodb.service;

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.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
import java.util.Map;

@Service
@RequiredArgsConstructor
public class AggregationService {
    private final MongoTemplate mongoTemplate;  // 用于复杂查询的核心模板类

    /**
     * 统计指定用户的各类行为数量
     */
    public Map<String, Long> statUserBehaviorCount(Long userId) {
        // 1. 匹配条件:筛选指定用户的行为日志
        MatchOperation match = Aggregation.match(Criteria.where(“user_id”).is(userId));

        // 2. 分组:按行为类型分组,计数
        GroupOperation group = Aggregation.group(“behavior_type”)
                .count().as(“count”);  // 计数结果字段名:count

        // 3. 构建聚合管道
        Aggregation aggregation = Aggregation.newAggregation(match, group);

        // 4. 执行聚合查询
        AggregationResults<BehaviorStatDTO> results = mongoTemplate.aggregate(
                aggregation,
                “user_behavior”,  // 目标集合
                BehaviorStatDTO.class  // 结果映射的DTO类
        );

        // 5. 转换结果为Map(key:行为类型,value:数量)
        return results.getMappedResults().stream()
                .collect(Collectors.toMap(
                        BehaviorStatDTO::getBehaviorType,
                        BehaviorStatDTO::getCount
                ));
    }

    // 结果DTO类
    @Data
    public static class BehaviorStatDTO {
        private String behaviorType;
        private Long count;
    }
}

(2)聚合查询场景2:商品评论评分统计(按评分分组计算占比)

需求:统计指定商品的评论评分分布(如5分占比、4分占比等)。

/**
 * 统计指定商品的评论评分分布
 */
public Map<Integer, Double> statGoodsCommentScore(Long goodsId) {
    // 1. 匹配条件:筛选指定商品的评论
    MatchOperation match = Aggregation.match(Criteria.where(“goods_id”).is(goodsId));

    // 2. 分组:按评分分组,计数
    GroupOperation groupByScore = Aggregation.group(“score”)
            .count().as(“scoreCount”);

    // 3. 计算总评论数(子聚合)
    GroupOperation groupTotal = Aggregation.group()
            .push(“$$ROOT”).as(“scoreList”)  // 保存分组结果
            .count().as(“totalCount”);  // 总评论数

    // 4. 展开scoreList(便于后续计算占比)
    UnwindOperation unwind = Aggregation.unwind(“scoreList”);

    // 5. 计算占比(scoreCount / totalCount)
    ProjectionOperation project = Aggregation.project()
            .and(“scoreList.score”).as(“score”)
            .andExpression(“round( (scoreList.scoreCount / totalCount) * 100, 2 )”).as(“rate”);  // 保留2位小数

    // 6. 构建聚合管道
    Aggregation aggregation = Aggregation.newAggregation(
            match, groupByScore, groupTotal, unwind, project
    );

    // 7. 执行查询并转换结果
    AggregationResults<ScoreRateDTO> results = mongoTemplate.aggregate(
            aggregation, “goods_comment”, ScoreRateDTO.class
    );

    return results.getMappedResults().stream()
            .collect(Collectors.toMap(
                    ScoreRateDTO::getScore,
                    ScoreRateDTO::getRate
            ));
}

// 评分占比DTO
@Data
public static class ScoreRateDTO {
    private Integer score;
    private Double rate;  // 占比(百分比)
}

2. 地理空间查询

MongoDB 原生支持地理空间索引和查询,适合“附近的人”、“附近的评论”、“范围检索”等场景。其核心是依赖 GeoJSON 格式来存储地理坐标(如 Point 点、Polygon 多边形)。

(1)创建地理空间索引

首先需要为 goods_comment 集合的 location 字段创建 2dsphere 索引(支持球面地理空间查询):

package com.example.mongodb.config;

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.index.GeospatialIndex;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;

/**
 * MongoDB索引配置(地理空间索引)
 */
@Component
@RequiredArgsConstructor
public class MongoIndexConfig {
    private final MongoTemplate mongoTemplate;

    @PostConstruct
    public void createIndex() {
        // 为goods_comment集合的location字段创建2dsphere索引
        mongoTemplate.indexOps(“goods_comment”)
                .ensureIndex(new GeospatialIndex(“location”));
        System.out.println(“MongoDB地理空间索引创建完成”);
    }
}

(2)地理空间查询场景1:查询指定位置附近的商品评论

需求:查询距离指定经纬度(如经度120.12,纬度30.33)5公里范围内的商品评论,按距离升序排序。

package com.example.mongodb.service;

import com.example.mongodb.entity.GoodsComment;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
import java.util.List;

@Service
@RequiredArgsConstructor
public class GeoSpatialService {
    private final MongoTemplate mongoTemplate;

    /**
     * 查询指定位置附近的商品评论
     * @param longitude 经度
     * @param latitude 纬度
     * @param distance 距离(单位:米)
     * @return 评论列表(按距离升序)
     */
    public List<GoodsComment> findNearbyComments(double longitude, double latitude, double distance) {
        // 1. 构建地理空间查询条件:查询指定点附近的文档
        Criteria criteria = Criteria.where(“location”)
                .nearSphere(Criteria.where(“location”)
                        .geometry(new GeoJsonPoint(longitude, latitude)))  // 中心点
                .maxDistance(distance);  // 最大距离(米)

        // 2. 构建查询对象,按距离升序排序
        Query query = Query.query(criteria)
                .with(Sort.by(Sort.Direction.ASC, “distance”));  // 按距离升序

        // 3. 执行查询
        return mongoTemplate.find(query, GoodsComment.class, “goods_comment”);
    }
}

(3)地理空间查询场景2:查询指定区域内的商品评论

需求:查询位于指定多边形区域内的商品评论(例如某个城市的特定区域)。

/**
 * 查询指定多边形区域内的商品评论
 * @param polygonCoordinates 多边形顶点经纬度(格式:[[x1,y1],[x2,y2],...,[x1,y1]])
 * @return 评论列表
 */
public List<GoodsComment> findCommentsInPolygon(List<double[]> polygonCoordinates) {
    // 1. 构建多边形GeoJSON对象
    GeoJsonPolygon polygon = new GeoJsonPolygon(polygonCoordinates);

    // 2. 构建查询条件:文档的location在多边形内
    Criteria criteria = Criteria.where(“location”)
            .within(polygon);

    // 3. 执行查询
    Query query = Query.query(criteria);
    return mongoTemplate.find(query, GoodsComment.class, “goods_comment”);
}

五、关键优化与问题解决

1. 性能优化核心要点

  • 索引优化:为高频查询字段(如 userIdgoodsIdscore)创建索引,地理空间查询必须创建 2dsphere 索引。
  • 连接池优化:根据实际并发量调整最大连接数、最小空闲连接数,避免连接耗尽。
  • 查询优化
    • 避免查询不必要的字段(使用 fields 指定返回字段)。
    • 大集合查询务必使用分页,避免一次性加载大量数据。
    • 复杂查询优先使用聚合管道,减少客户端与数据库的交互次数。
  • 数据分片:在海量数据场景下,应使用 MongoDB 分片集群(Sharding),按分片键拆分数据,以提升横向扩展和并发处理能力。

2. 常见问题与解决方案

  • 数据一致性问题:MongoDB 默认是最终一致性。在单节点部署下,可通过 writeConcern(写关注)来保证写入的持久化(例如 w: 1 表示等待主节点确认写入)。
  • 索引失效问题:查询条件中如果使用了字段类型转换、正则匹配(如 /xxx/)可能导致索引失效,需要合理设计查询条件。
  • 地理空间查询精度问题:确保存储的经纬度格式正确([经度, 纬度]),并使用 2dsphere 索引而非 2d 索引(2d 索引适用于平面坐标,精度较低)。
  • 大文档处理:避免存储过大的文档(建议单文档小于 16MB),可以拆分大文档为多个小文档,通过关联字段进行关联。

3. 高可用部署建议

生产环境中,为避免 MongoDB 单点故障,推荐部署主从复制+哨兵MongoDB 副本集(Replica Set)

  • 副本集(Replica Set):包含 1 个主节点(Primary)和多个从节点(Secondary)。主节点负责写操作,从节点同步主节点数据并提供读服务。当主节点故障时,集群会自动选举出新的主节点。
  • 配置调整:Spring Boot 连接副本集时,需要修改 MongoDB 连接 URI,格式例如:mongodb://user:password@host1:port1,host2:port2,host3:port3/db?replicaSet=副本集名称&authSource=db



上一篇:Java 2025年底招聘现状:高薪Offer背后,面试辅导如何成为关键变量?
下一篇:Linux内核调试:详解dev_dbg运行时重启的原理与实战
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-11 14:18 , Processed in 0.216169 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表