SpringBoot实现MongoDB数组字段匹配查询集合数据方案
实现方案
首先说下你现在的集合设计是合理的:同结构不同分类的数据合并到一个集合,用数组字段存分类标签,比拆成多个零散集合好维护,后续加新分类不用新建集合,扩展查询也方便。
1. 实体Model定义
你现在写的字段映射基本正确,补个MongoDB的集合映射注解就行,数组字段推荐换成List<String>,比原生String数组更适配Java的集合操作,和MongoDB的数组存储格式完全兼容:
import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import java.util.List; // 绑定MongoDB里的PackageHoliday集合 @Document(collection = "PackageHoliday") public class PackageHoliday { @Id private String id; private String title; private String description; private String whatToDo; private List<String> packageHolidayType; // 自己补全getter、setter、构造函数,用Lombok的话直接类上加@Data注解省得写重复代码 }
2. 查询逻辑实现
两种写法选其一即可,简单场景优先用方法名派生查询,不用写额外实现代码:
第一种:直接继承MongoRepository写接口,Spring Data会自动根据方法名生成查询规则:
import org.springframework.data.mongodb.repository.MongoRepository; import java.util.List; public interface PackageHolidayRepository extends MongoRepository<PackageHoliday, String> { // 规则:查询packageHolidayType数组中包含传入分类值的所有文档 List<PackageHoliday> findByPackageHolidayTypeContaining(String holidayType); }
如果你的接口要实现「随机返回N条」的逻辑(从你写的接口名带Random判断有这个需求),用MongoTemplate写个聚合查询就行,把这段逻辑封装到Service层:
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.query.Criteria; import org.springframework.stereotype.Service; import java.util.List; @Service public class PackageHolidayService { @Autowired private MongoTemplate mongoTemplate; @Autowired private PackageHolidayRepository holidayRepository; // 按分类查全量数据 public List<PackageHoliday> getListByType(String type) { return holidayRepository.findByPackageHolidayTypeContaining(type); } /** * 随机获取指定分类的N条套餐数据 * @param type 分类值 * @param limit 返回条数 */ public List<PackageHoliday> getRandomByType(String type, int limit) { Aggregation agg = Aggregation.newAggregation( // 第一步:过滤出匹配分类的文档 Aggregation.match(Criteria.where("packageHolidayType").is(type)), // 第二步:随机抽样指定条数 Aggregation.sample(limit) ); return mongoTemplate.aggregate(agg, "PackageHoliday", PackageHoliday.class).getMappedResults(); } }
3. 控制器接口实现
不推荐为每个分类写重复的接口逻辑,把分类作为路径参数做通用接口就行,后续加新分类不用改代码;如果你一定要保留独立的接口地址,直接复用通用逻辑传固定参数即可。
推荐写法:通用接口
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/api/holiday") public class PackageHolidayController { @Autowired private PackageHolidayService holidayService; // 按分类查全量,例:请求 /api/holiday/type/escortedTours 就返回所有跟团游数据 @GetMapping("/type/{holidayType}") public List<PackageHoliday> getListByType(@PathVariable String holidayType) { return holidayService.getListByType(holidayType); } // 按分类随机取N条,例:/api/holiday/random/escortedTours?limit=3 随机返回3条跟团游 @GetMapping("/random/{holidayType}") public List<PackageHoliday> getRandomByType(@PathVariable String holidayType, @RequestParam(defaultValue = "3") int limit) { return holidayService.getRandomByType(holidayType, limit); } }
适配你现有框架的写法
如果你要保留你之前写的/getRandomEscortedTours独立接口,直接调用Service方法传固定参数就行,不用重复写查询:
@GetMapping("/getRandomEscortedTours") public List<PackageHoliday> getRandomEscortedTours() { return holidayService.getRandomByType("escortedTours", 3); } // 其他分类的独立接口同理,直接传对应分类值 @GetMapping("/getRandomIndependentTours") public List<PackageHoliday> getRandomIndependentTours() { // 注意:你示例数据里的indepedentTours拼写少了个n,代码里的参数要和库里存的值完全一致,不然查不到数据 return holidayService.getRandomByType("indepedentTours", 3); }
踩坑提醒:注意核对库里存储的分类值拼写,示例数据里的独立游分类值是
indepedentTours(正确拼写应为independentTours,少了一个n),代码里的查询参数必须和库内存储值完全匹配,否则会返回空结果。
内容的提问来源于stack exchange,提问作者devnoob
相关产品推荐
相关产品推荐

