Is it possible to rename _id field after mongo's group aggregation?
JavaMongodbAggregation FrameworkRenameJava Problem Overview
I have a query like this (simplified):
db.collection.aggregate([
{ $match: { main_id: ObjectId("58f0f67f50c6af16709fd2c7") } },
{
$group: {
_id: "$name",
count: { $sum: 1 },
sum: { $sum: { $add: ["$P31", "$P32"] } }
}
}
])
I do this query from Java, and I want to map it on my class, but I don't want _id
to be mapped on name
field. Because if I do something like this:
@JsonProperty("_id")
private String name;
then when I save this data back to mongo (after some modification) the data is saved with name as _id
while I want a real Id to be generated.
So, how can I rename _id
after $group
operation?
Java Solutions
Solution 1 - Java
You can achieve this by adding a $project
stage at the end of your pipeline like this :
{ $project: {
_id: 0,
name: "$_id",
count: 1,
sum: 1
}
}
try it online: mongoplayground.net/p/QpVyh-0I-bP
Solution 2 - Java
From mongo v3.4 you could use $addFields
in conjunction with $project
to avoid to write all the fields in $project
that could be very tedious.
This happen in $project
because if you include specifically a field, the other fields will be automatically excluded.
Example:
{
$addFields: { my_new_id_name: "$_id" }
},
{
$project: { _id: 0 }
}
Solution 3 - Java
db.report.aggregate(
{
$group: {_id: '$name'}
},
{
$project:{
name:"$_id",
_id:false} }
)
Solution 4 - Java
if you are using find
method you can't do this, but if you using aggregation
it is very easy like this:
db.collectionName.aggregate([
{
$project: {
newName: "$existingKeyName"
}
}
]);
Solution 5 - Java
Starting in Mongo 4.2
, you can use a combination of $set
/ $unset
stages:
// { x: 1, z: "a" }
// { x: 2, z: "b" }
db.collection.aggregate([ { $set: { y: "$x" } }, { $unset: "x" }])
// { y: 1, z: "a" }
// { y: 2, z: "b" }
The $set
stage adds the new field to documents and the $unset
stage removes/excludes the field to be renamed from documents.
Solution 6 - Java
As all of the answers are written the solution in MongoDB query despite the question seeks the solution in Java, posting my approach using Java for posterities.
After the grouping, we can rename the _id
fieldname using
Projections.computed("<expected field name>", "$_id")))
To Transform the core part of the query mentioned in the question to Java
Bson mainIdMatch = match(eq("main_id", new ObjectId("58f0f67f50c6af16709fd2c7")));
Bson group = Aggregates.group("$name", Accumulators.sum("count", 1L));
Bson project = Aggregates.project(Projections.fields(Projections.excludeId(),
Projections.computed("name", "$_id")));
reportMongoCollection.aggregate(Arrays.asList(mainIdMatch, group, project))
.into(new ArrayList<>());
To answer specifically, I have added an excerpt from the above code snippet, where I am renaming _id
field value as name using Projections.computed("name", "$_id")
which map the values of _id
which we got as a result of grouping to the field called name
. Also, we should exclude the id using Projections.excludeId()
.
Aggregates.project(Projections.fields(Projections.excludeId(),
Projections.computed("name", "$_id")))