我正在使用 MongoDB 聚合在 Spring Data Mongo 项目中实现分页。检索数据时,结果中的字段全部返回为空,我很难理解为什么。
环境:
问题描述: 数据已成功存储在 MongoDB 中,并且我已经使用聚合框架设置了分页。然而,检索到的对象中的字段在结果中全部为空。
代码详情:
标签类
@Document(collection = "labels")
public class Label extends BaseDocument {
private LabelType type;
private String path;
private ObjectId datasetId;
private String annotations;
// Constructors, getters, setters...
}
存储库代码
@Repository
public class LabelRepositoryCustomImpl implements LabelRepositoryCustom {
private final MongoTemplate mongoTemplate;
@Override
public Page<Label> findAllWithPagination(Pageable pageable, ObjectId datasetId) {
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("datasetId").is(datasetId)),
Aggregation.sort(pageable.getSort()),
Aggregation.facet(
Aggregation.count().as("totalCount"),
Aggregation.skip((long) pageable.getPageNumber() * pageable.getPageSize()),
Aggregation.limit(pageable.getPageSize())
).as("metadata")
);
AggregationResults<Label> results = mongoTemplate.aggregate(aggregation, "labels", Label.class);
List<Label> labels = results.getMappedResults();
return PageableExecutionUtils.getPage(labels, pageable, labels::size);
}
}
Mongo聚合查询
{
"aggregate" : "labels",
"pipeline" : [
{ "$match" : { "datasetId" : { "$oid" : "672ac21827cf3f529bbb5a57"}}},
{ "$sort" : { "createdAt" : -1}},
{ "$facet" : {
"metadata" : [
{ "$count" : "totalCount"},
{ "$skip" : 0},
{ "$limit" : 10}
]
}}
]
}
问题:
任何指导将不胜感激。谢谢!
问题似乎是您的类
Label
与输出查询不匹配。您的查询返回这样的结构:
{
metadata: [
{ totalCount: 100 }
]
}
你的班级有这样的结构:
{
type: ""
path: ""
datasetId: ""
annotations: ""
}
因此您将丢失文档的所有先前字段,因为
$facet
:
在同一组输入文档的单个阶段内处理多个聚合管道。每个子管道在输出文档中都有自己的字段,其结果存储为文档数组。
来源:https://www.mongodb.com/docs/v6.1/reference/operator/aggregation/facet/
我可以建议使用 MongoRepository 而不使用 MongoTemplate 吗?
这样的例子:
import org.bson.types.ObjectId;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
public interface LabelRepository extends MongoRepository<Label, ObjectId> {
@Query("{ 'datasetId': ?0 }")
Page<Label> findByDatasetId(ObjectId datasetId, Pageable pageable);
}
这将自动返回
Page
。
如果您想将聚合与 mongoTemplate 一起使用,您必须运行 2 个查询(一个计数,一个用于页面),如下所示:
@Repository
public class LabelRepositoryCustomImpl implements LabelRepositoryCustom {
private final MongoTemplate mongoTemplate;
@Autowired
public LabelRepositoryCustomImpl(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
@Override
public Page<Label> findAllWithPagination(Pageable pageable, ObjectId datasetId) {
// Conteggio totale dei documenti
long total = countByDatasetId(datasetId);
// Aggregazione per la paginazione
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("datasetId").is(datasetId)),
Aggregation.sort(pageable.getSort()),
Aggregation.skip((long) pageable.getPageNumber() * pageable.getPageSize()),
Aggregation.limit(pageable.getPageSize())
);
AggregationResults<Label> results = mongoTemplate.aggregate(aggregation, "labels", Label.class);
List<Label> labels = results.getMappedResults();
return new PageImpl<>(labels, pageable, total);
}
private long countByDatasetId(ObjectId datasetId) {
// Aggregazione per il conteggio totale dei documenti
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("datasetId").is(datasetId)),
Aggregation.count().as("total")
);
AggregationResults<CountResult> results = mongoTemplate.aggregate(aggregation, "labels", CountResult.class);
CountResult countResult = results.getUniqueMappedResult();
return countResult != null ? countResult.getTotal() : 0;
}
static class CountResult {
private long total;
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
}
}
在我看来,很多代码行都是不必要的。
希望这对你有帮助