I am new to MongoDB. I have a collection like:
[
{
"_id":"1",
"travels":[
{
"_id":"1"
},
{
"_id":"2"
},
{
"_id":"3"
}
]
},
{
"_id":"2",
"travels":[
{
"_id":"4"
},
{
"_id":"5"
},
{
"_id":"6"
}
]
}
]
My Java model is more or less like this (using public modifiers for simplicity):
public class TravelsDocument<T> {
@Id
public String id;
public List<Travel> travels;
}
public class Travel {
public String id;
}
All ids in travels arrays are unique. In my Spring application I would like to select a single travel
element matching specified id.
I’ve finally figured out how to do that in MongoDB.
First, I applied a filter:
{travels: {$elemMatch: { _id: 'someId'}}}
and then a projection:
{
"_id":0,
"travel":{
"$arrayElemAt":[
"$travels",
{
"$indexOfArray":[
"$travels._id",
"someId"
]
}
]
}
}
Then I tried to use it in an aggregation:
@Aggregation(pipeline = {
"{'$match' :{'travels': {$elemMatch: { _id: :#{#id}}}}}",
"{'$project' :{_id:0, 'travel':{$arrayElemAt: [ '$travels', {$indexOfArray :['$travels._id', :#{#id}]} ] }}}"})
Mono<Travel> findSingleTravelByTenantAndId(@Param("id") String id);
The issue is that this method doesn’t return my Travel
object but rather org.bson.Document
object. Is there a way to return my custom object using Aggregation annotation? Is this the way to go?
2
Answers
The final projection stage of the aggregation pipeline would return documents as
{ travel: { _id: 123 } }
– note the outertravel
field. But that’s not the structure of yourTravel
class, it only definesid
(which I presume maps to_id
), and probably other fields/members.So you need to add a
$replaceWith
stage:Or better, remove the project stage and use replaceWith instead:
So the full pipeline would be:
Mongo Playground
This is a variation of the query. Produces the result for the filter field
travels._id
value is'4'
:The output:
[ { _id: '4' } ]