Spring 数据 MongoDB 聚合 - 在投影中重命名 _id
Spring Data MongoDB Aggregation - rename _id in projection
在 mongo (3.6) shell 中,我可以执行以下聚合来投影并将“_id”重命名为其他名称:
db.collection.aggregate([
{ $group : { _id : ... },
{ $project : { '_id': 0, // exclude the id field
'name' : '$_id', // project the "old" id value to the "name" field
...
}
}
])
我需要使用 spring-data-mongo(通过 Spring Boot 2.3.1)来翻译它。
我可以使用以下 ProjectionOperation:
排除 id 字段
project().andExclude("_id")
但到目前为止我无法重命名 id 字段。
None 以下作品:
我的第一个猜测
project().and("_id").as("name")
按照建议here
project().andExpression("_id").as("name")
应该没那么难,但我不知道我错过了什么。
编辑:数据样本和完整聚合管道重现失败
具有以下文件:
{
"_id" : ObjectId("5a0c7a3135587511c9247db4"),
"_class" : "task",
"category" : "green",
"status" : "OK"
}
{
"_id" : ObjectId("5a0cd21d35587511c9247db8"),
"_class" : "task",
"category" : "red",
"status" : "KO"
}
域对象:
@Document(collection = "tasks")
@TypeAlias("task")
public class Task {
@Id
private String id;
private String status;
private String category;
// getters/setters omitted
}
以及以下聚合:
Aggregation a = Aggregation.newAggregation(
group("status", "category").count().as("count"),
group("_id.category").push(
new Document("k", "$_id.status").append("v", "$count"))
.as("counts"),
project().and(arrayToObject("$counts")).as("counts"),
// this final stage fails with: a java.lang.IllegalArgumentException: Invalid reference '_id'!
project().and("_id").as("name").andExclude("_id")
);
mongotemplate.aggregate(a, "tasks", org.bson.Document.class)
在最后一个管道阶段之前,聚合给出:
[ { "_id" : "green", "counts" : { "OK" : 1 } },
{ "_id" : "red", "counts" : { "KO" : 1 } } ]
所以我们应该能够将“_id”投影到“name”,但我们得到的是:
java.lang.IllegalArgumentException: Invalid reference '_id'!
at org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext.getReference(ExposedFieldsAggregationOperationContext.java:114) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext.getReference(ExposedFieldsAggregationOperationContext.java:77) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.ProjectionOperation$ProjectionOperationBuilder$FieldProjection.renderFieldValue(ProjectionOperation.java:1445) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.ProjectionOperation$ProjectionOperationBuilder$FieldProjection.toDocument(ProjectionOperation.java:1432) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.ProjectionOperation.toDocument(ProjectionOperation.java:261) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.AggregationOperation.toPipelineStages(AggregationOperation.java:55) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.AggregationOperationRenderer.toDocument(AggregationOperationRenderer.java:56) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.Aggregation.toPipeline(Aggregation.java:721) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.AggregationUtil.createPipeline(AggregationUtil.java:95) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.MongoTemplate.doAggregate(MongoTemplate.java:2118) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:2093) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1992) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
我已经找到了解决方法(见下文),但我仍然很好奇为什么上面显示的聚合会失败。我不明白为什么“_id”引用没有正确公开。
成功的解决方法:
Aggregation a = Aggregation.newAggregation(
group("status", "category").count().as("count"),
group("_id.category").push(
new Document("k", "$_id.status").append("v", "$count"))
.as("counts"),
project().and(arrayToObject("$counts")).as("counts"),
// the following works
addFields().addFieldWithValue("name", "$_id").build(),
project().andExclude("_id").andExclude("counts")
);
对于无法确定谁将 MongoDB 聚合转换为 Spring 数据 Mongo 聚合时需要解决方法的任何人:
试试这个:
project("_id").and(arrayToObject("$counts")).as("counts"),
project().andExclude("_id").and("_id").as("name")
编辑:
Spring-Mongo 对您的管道进行一些验证,并期望 _id
存在于您的前一阶段,因此这就是 java.lang.IllegalArgumentException: Invalid reference '_id'!
[=15= 的原因]
Aggregation agg = Aggregation.newAggregation(
group("status", "category").count().as("count"),
group("_id.category").push(new Document("k", "$_id.status").append("v", "$count")).as("counts"),
project("_id").and(ArrayOperators.arrayOf("$counts").toObject()).as("counts"),
project().and("_id").as("name").andExclude("_id"));
AggregationResults<Document> results = mongoTemplate.aggregate(agg, "tasks", Document.class);
results.getMappedResults().forEach(System.out::println);
---输出---
Document{{name=green}}
Document{{name=red}}
在 mongo (3.6) shell 中,我可以执行以下聚合来投影并将“_id”重命名为其他名称:
db.collection.aggregate([
{ $group : { _id : ... },
{ $project : { '_id': 0, // exclude the id field
'name' : '$_id', // project the "old" id value to the "name" field
...
}
}
])
我需要使用 spring-data-mongo(通过 Spring Boot 2.3.1)来翻译它。 我可以使用以下 ProjectionOperation:
排除 id 字段project().andExclude("_id")
但到目前为止我无法重命名 id 字段。 None 以下作品:
我的第一个猜测
project().and("_id").as("name")
按照建议here
project().andExpression("_id").as("name")
应该没那么难,但我不知道我错过了什么。
编辑:数据样本和完整聚合管道重现失败
具有以下文件:
{
"_id" : ObjectId("5a0c7a3135587511c9247db4"),
"_class" : "task",
"category" : "green",
"status" : "OK"
}
{
"_id" : ObjectId("5a0cd21d35587511c9247db8"),
"_class" : "task",
"category" : "red",
"status" : "KO"
}
域对象:
@Document(collection = "tasks")
@TypeAlias("task")
public class Task {
@Id
private String id;
private String status;
private String category;
// getters/setters omitted
}
以及以下聚合:
Aggregation a = Aggregation.newAggregation(
group("status", "category").count().as("count"),
group("_id.category").push(
new Document("k", "$_id.status").append("v", "$count"))
.as("counts"),
project().and(arrayToObject("$counts")).as("counts"),
// this final stage fails with: a java.lang.IllegalArgumentException: Invalid reference '_id'!
project().and("_id").as("name").andExclude("_id")
);
mongotemplate.aggregate(a, "tasks", org.bson.Document.class)
在最后一个管道阶段之前,聚合给出:
[ { "_id" : "green", "counts" : { "OK" : 1 } },
{ "_id" : "red", "counts" : { "KO" : 1 } } ]
所以我们应该能够将“_id”投影到“name”,但我们得到的是:
java.lang.IllegalArgumentException: Invalid reference '_id'!
at org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext.getReference(ExposedFieldsAggregationOperationContext.java:114) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext.getReference(ExposedFieldsAggregationOperationContext.java:77) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.ProjectionOperation$ProjectionOperationBuilder$FieldProjection.renderFieldValue(ProjectionOperation.java:1445) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.ProjectionOperation$ProjectionOperationBuilder$FieldProjection.toDocument(ProjectionOperation.java:1432) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.ProjectionOperation.toDocument(ProjectionOperation.java:261) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.AggregationOperation.toPipelineStages(AggregationOperation.java:55) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.AggregationOperationRenderer.toDocument(AggregationOperationRenderer.java:56) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.aggregation.Aggregation.toPipeline(Aggregation.java:721) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.AggregationUtil.createPipeline(AggregationUtil.java:95) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.MongoTemplate.doAggregate(MongoTemplate.java:2118) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:2093) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1992) ~[spring-data-mongodb-3.0.1.RELEASE.jar:3.0.1.RELEASE]
我已经找到了解决方法(见下文),但我仍然很好奇为什么上面显示的聚合会失败。我不明白为什么“_id”引用没有正确公开。
成功的解决方法:
Aggregation a = Aggregation.newAggregation(
group("status", "category").count().as("count"),
group("_id.category").push(
new Document("k", "$_id.status").append("v", "$count"))
.as("counts"),
project().and(arrayToObject("$counts")).as("counts"),
// the following works
addFields().addFieldWithValue("name", "$_id").build(),
project().andExclude("_id").andExclude("counts")
);
对于无法确定谁将 MongoDB 聚合转换为 Spring 数据 Mongo 聚合时需要解决方法的任何人:
试试这个:
project("_id").and(arrayToObject("$counts")).as("counts"),
project().andExclude("_id").and("_id").as("name")
编辑:
Spring-Mongo 对您的管道进行一些验证,并期望 _id
存在于您的前一阶段,因此这就是 java.lang.IllegalArgumentException: Invalid reference '_id'!
[=15= 的原因]
Aggregation agg = Aggregation.newAggregation(
group("status", "category").count().as("count"),
group("_id.category").push(new Document("k", "$_id.status").append("v", "$count")).as("counts"),
project("_id").and(ArrayOperators.arrayOf("$counts").toObject()).as("counts"),
project().and("_id").as("name").andExclude("_id"));
AggregationResults<Document> results = mongoTemplate.aggregate(agg, "tasks", Document.class);
results.getMappedResults().forEach(System.out::println);
---输出---
Document{{name=green}}
Document{{name=red}}