如何在Morphia中查询PlayerStatisticsData并过滤transactions子数组
查询PlayerStatisticsData并过滤嵌套的PlayerTransaction列表
下面分不同技术栈给出具体实现方案:
一、JPA/Hibernate(关系型数据库场景)
如果你的项目用JPA关联实体(PlayerStatisticsData和PlayerTransaction是一对多关系),可以用以下两种方式过滤嵌套的transactions列表:
1. 自定义DTO+JPQL投影
先创建一个DTO类,用来封装查询结果:
public class PlayerStatsDto { private Long id; private String playerName; // 替换成你的实际字段 private List<PlayerTransaction> recentTransactions; // 对应JPQL查询的构造函数 public PlayerStatsDto(Long id, String playerName, List<PlayerTransaction> recentTransactions) { this.id = id; this.playerName = playerName; this.recentTransactions = recentTransactions; } // getter、setter按需添加 }
然后在Repository中写JPQL查询:
@Repository public interface PlayerStatisticsDataRepository extends JpaRepository<PlayerStatisticsData, Long> { @Query("SELECT new com.yourpackage.dto.PlayerStatsDto(ps.id, ps.playerName, " + "(SELECT pt FROM PlayerTransaction pt WHERE pt.playerStats = ps AND pt.timestamp > :cutoffTime)) " + "FROM PlayerStatisticsData ps") List<PlayerStatsDto> findWithRecentTransactions(@Param("cutoffTime") LocalDateTime cutoffTime); }
这种方式直接查询出过滤后的结果,避免加载所有冗余的Transaction数据。
2. Hibernate过滤器
在PlayerTransaction实体上定义过滤器规则:
@Entity @FilterDef(name = "filterRecentTransactions", parameters = @ParamDef(name = "cutoffTime", type = LocalDateTime.class)) @Filter(name = "filterRecentTransactions", condition = "timestamp > :cutoffTime") public class PlayerTransaction { @Id private Long id; private LocalDateTime timestamp; @ManyToOne private PlayerStatisticsData playerStats; // 其他字段和方法 }
查询时启用过滤器:
// 从EntityManager获取Hibernate Session Session session = entityManager.unwrap(Session.class); // 启用过滤器并设置时间参数 session.enableFilter("filterRecentTransactions") .setParameter("cutoffTime", LocalDateTime.now().minusDays(7)); // 示例:近7天的数据 // 此时查询出来的PlayerStatisticsData,其transactions列表只会包含符合条件的记录 List<PlayerStatisticsData> statsList = session.createQuery("FROM PlayerStatisticsData", PlayerStatisticsData.class).list();
二、MongoDB(Spring Data MongoDB场景)
如果是MongoDB文档库,嵌套数组的过滤更加灵活,推荐用聚合管道或者投影查询:
1. 聚合管道过滤
// 构建聚合管道 Aggregation aggregation = Aggregation.newAggregation( // 可选:先匹配目标PlayerStatisticsData(比如按ID筛选) Aggregation.match(Criteria.where("_id").is(playerStatsId)), // 投影时过滤transactions数组 Aggregation.project() .andInclude("playerName", "level") // 保留你需要的其他根字段 .and(Aggregation.filter("transactions", "this.timestamp > :cutoffTime")) .as("transactions") ); // 执行聚合查询 AggregationResults<PlayerStatisticsData> results = mongoTemplate.aggregate( aggregation, "playerStatisticsData", // 集合名 PlayerStatisticsData.class ); PlayerStatisticsData filteredStats = results.getUniqueMappedResult();
2. 直接用Query投影
Query query = new Query(); // 可选:添加根文档的筛选条件 query.addCriteria(Criteria.where("_id").is(playerStatsId)); // 过滤transactions数组 query.fields().project("transactions", Aggregation.filter("transactions", "this.timestamp > ?0", cutoffTime)); PlayerStatisticsData filteredStats = mongoTemplate.findOne(query, PlayerStatisticsData.class);
三、关键注意事项
- 索引优化:不管用哪种数据库,都要给PlayerTransaction的timestamp字段建立索引,大幅提升过滤查询的速度
- 批量查询性能:JPA场景下批量查询时,避免N+1问题,优先用构造函数投影的方式;MongoDB场景下聚合管道要注意避免不必要的阶段
内容的提问来源于stack exchange,提问作者Batimonster
相关产品推荐
相关产品推荐

