SpringBoot/Java如何统计设备数量并返回Map<String,Map<String,Map<String,Long>>>结果
实现方案
方案1:查询全量数据后用Stream流聚合(最简便,适合数据量不大的场景)
你先把所有Device数据从库中查出来得到List<Device> deviceList,之后直接用Java 8+的Stream流式API配合Collectors.groupingBy嵌套聚合即可,一行代码就能得到你要的三层Map结构,完全不用写嵌套for循环:
// 结果结构:Map<Type类型, Map<Constructor类型, Map<Model类型, 设备数量>>> // 这里假设三个字段都是String类型,你可以根据实际字段类型调整泛型 Map<String, Map<String, Map<String, Long>>> result = deviceList.stream() // 第一层分组:按Type字段分组 .collect(Collectors.groupingBy(Device::getType, // 第二层分组:相同Type下按Constructor字段分组 Collectors.groupingBy(Device::getConstructor, // 第三层分组:相同Type+Constructor下按Model分组,统计每组数量 Collectors.groupingBy(Device::getModel, Collectors.counting()))));
方案2:数据库层面先分组统计,再转嵌套Map(适合数据量大的场景)
如果表内数据量太大,全量查询拉到内存处理会占用过多资源,可以先在数据库层面做分组统计,再把结果转成三层Map,性能更高:
SQL示例(以MySQL为例)
SELECT type, constructor, model, COUNT(*) AS cnt FROM device GROUP BY type, constructor, model;
结果转换逻辑
假设你把查询结果封装成了DeviceStat实体类,对应type、constructor、model、cnt四个字段,拿到结果列表List<DeviceStat> statList后,还是用Stream处理即可:
Map<String, Map<String, Map<String, Long>>> result = statList.stream() .collect(Collectors.groupingBy(DeviceStat::getType, Collectors.groupingBy(DeviceStat::getConstructor, Collectors.toMap(DeviceStat::getModel, DeviceStat::getCnt))));
如果你用的是MyBatis-Plus,也可以直接用LambdaQueryWrapper完成分组查询,不用手写SQL:
List<Map<String, Object>> statList = deviceMapper.selectMaps(Wrappers.lambdaQuery(Device.class) .select(Device::getType, Device::getConstructor, Device::getModel) .select("count(*) as cnt") .groupBy(Device::getType, Device::getConstructor, Device::getModel));
注意事项
如果三个分组字段存在NULL值,建议提前过滤或者做默认值替换,避免生成的Map出现NULL键不符合你的业务要求。
内容的提问来源于stack exchange,提问作者Nivwok
相关产品推荐
相关产品推荐

