我正在尝试使用 Spring Data Mongo 来获取文档集合中某些字段的平均值。我有一个通过 Atlas 搜索进行搜索的管道,然后是一个执行平均值的小组阶段。
{
"_id": {"$oid": "65ea0c9d638cd57f51c22cb7"},
"listing": {
"listingId": 709834373,
"listDate": {"$date": "2023-10-12T00:00:00.000Z"},
"price": {
"currencyCode": "USD",
"value": 1000
},
}
}
public Optional<SummaryData> searchResultsSummaryData(SearchFilter searchFilter) {
SearchOperation searchOperation = buildSearchOperationFromFilter(searchFilter);
SearchAggregation searchAggregation = SearchAggregation.builder()
.searchOperation(searchOperation)
.build();
Document aggregationDoc = new Document();
mongoConverter.write(searchAggregation, aggregationDoc);
GroupOperation groupOperation = group("listing.price.value").avg("$avg(listing.price.value)").as("avgPrice");
Document groupDoc = new Document();
mongoConverter.write(groupOperation, groupDoc);
log.debug("groupDoc: {}", groupDoc.toJson());
Document groupStage = new Document("$group", groupDoc);
Document projectDocDetail = new Document("avgPrice", 1);
Document projectDoc = new Document("$project", projectDocDetail);
MongoCollection<Document> collection = mongoOperations.getCollection(LISTING_DOCUMENT.collection());
List<Document> aggList = List.of(aggregationDoc, groupStage, projectDoc);
log.debug("aggList: {}", toJson(aggList));
AggregateIterable<Document> aggregationResult = collection.aggregate(aggList);
Document summaryDocument = aggregationResult.first();
if (summaryDocument == null) {
return Optional.empty();
} else {
return Optional.of(defaultMongoConverter.read(SummaryData.class, summaryDocument));
}
}
但是当我运行这个时,我得到了这个异常:
com.mongodb.MongoCommandException: Command failed with error 40234 (Location40234): 'The field 'idFields' must be an accumulator object' on server pl-1-us-west-2.c8foo.mongodb.net:1037. The full response is {"ok": 0.0, "errmsg": "The field 'idFields' must be an accumulator object", "code": 40234, "codeName": "Location40234", "$clusterTime": {"clusterTime": {"$timestamp": {"t": 1719546021, "i": 8}}, "signature": {"hash": {"$binary": {"base64": "rOfPFKpgglg5DigfTjeL2n1qgeg=", "subType": "00"}}, "keyId": 7329363855287517191}}, "operationTime": {"$timestamp": {"t": 1719546021, "i": 8}}}
at com.mongodb.internal.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:205) ~[mongodb-driver-core-4.11.2.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:454) ~[mongodb-driver-core-4.11.2.jar:na]
at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:372) ~[mongodb-driver-core-4.11.2.jar:na]
at com.mongodb.internal.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:114) ~[mongodb-driver-core-4.11.2.jar:na]
at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.sendAndReceive(DefaultConnectionPool.java:765) ~[mongodb-driver-core-4.11.2.jar:na]
如果我反序列化管道,我会收到以下查询:
[
{
"$search": {
...
}
},
{
"$group": {
"idFields": {
"originalFields": [
{
"synthetic": false,
"field": {
"raw": "listing.price.value",
"name": "price.value",
"target": "listing.price.value"
}
}
],
"syntheticFields": []
},
"operations": [
{
"op": "AVG",
"key": "avgPrice",
"reference": "$avg(listing.price.value)"
}
]
}
},
{
"$project": {
"avgPrice": 1
}
}
]
我可以手写一个小组赛阶段来完成我想要的事情:
$group: {
_id: null,
avgPrice: { $avg: "$listing.price.value" }
}
但是 Spring Data 的序列化方式完全不同。
我尝试将各种字段名称传递给
group()
方法,但基本上得到了相同的错误。
任何帮助将不胜感激。
您不应该在
group
方法中传递任何内容。
GroupOperation groupOperation = Aggregation.group().avg("listing.price.value").as("avgPrice");
生成的阶段是,
{
"$group":
{
"_id": null,
"avgPrice":
{
"$avg": "$listing.price.value"
}
}
}