如何在Spring Data Mongo的findAll()查询中使用{allowDiskUse: true}
遇到的异常:
com.mongodb.MongoQueryException: Query failed with error code 292 and error message 'Executor error during find command :: caused by :: Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting.'
Spring Data提供的CrudRepo.findAll()默认方法无法直接配置allowDiskUse: true,因为这类通用方法没有暴露MongoDB底层参数配置。不过可以通过以下两种方式实现需求:
自定义查询方法,借助MongoTemplate配置参数
如果是普通查询加排序场景,可通过MongoTemplate构建查询并开启磁盘使用:import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.domain.Sort; // 在Service或自定义Repository实现类中 public List<YourEntity> findAllWithDiskSorting() { Query query = new Query(); // 添加排序条件,示例为按createTime降序 query.with(Sort.by(Sort.Direction.DESC, "createTime")); // 开启allowDiskUse配置 query.withHint(new org.bson.Document("allowDiskUse", true)); return mongoTemplate.find(query, YourEntity.class); }如果涉及聚合操作,直接通过AggregationOptions开启磁盘使用:
import org.springframework.data.mongodb.core.aggregation.Aggregation; import org.springframework.data.mongodb.core.aggregation.AggregationOptions; public List<YourEntity> aggregateWithDiskUse() { Aggregation aggregation = Aggregation.newAggregation( Aggregation.sort(Sort.by("createTime").descending()) // 按需添加其他聚合步骤 ).withOptions(AggregationOptions.builder().allowDiskUse(true).build()); return mongoTemplate.aggregate(aggregation, "your_collection_name", YourEntity.class) .getMappedResults(); }扩展CrudRepository,自定义实现类
先定义自定义接口:public interface CustomYourEntityRepository { List<YourEntity> findAllWithAllowDiskUse(); }让CrudRepository继承该接口:
public interface YourEntityRepository extends CrudRepository<YourEntity, String>, CustomYourEntityRepository { }最后实现自定义接口,通过MongoTemplate完成查询:
public class CustomYourEntityRepositoryImpl implements CustomYourEntityRepository { private final MongoTemplate mongoTemplate; public CustomYourEntityRepositoryImpl(MongoTemplate mongoTemplate) { this.mongoTemplate = mongoTemplate; } @Override public List<YourEntity> findAllWithAllowDiskUse() { Query query = new Query(); query.withHint(new org.bson.Document("allowDiskUse", true)); return mongoTemplate.find(query, YourEntity.class); } }业务代码中即可直接调用
yourEntityRepository.findAllWithAllowDiskUse()启用磁盘排序。
注意:如果你的findAll()调用带有Sort参数(如findAll(Sort sort)),排序操作正是触发内存超限的核心原因,必须通过上述方式开启allowDiskUse才能绕过限制。
内容的提问来源于stack exchange,提问作者Sandeep Chakraborty

