Well, In Spring Data such kind of queries is not trivial.
Bad news:
Spring Data Repository does not have solution for MongoDB Aggregation. So, you cannot implement in MongoRepository any method to do so, like aggregateBy...
Good news:
Spring Data provides MongoTemplate class which allows you to execute complex queries, like you would do in standard MongoDB shell.
So, as you just want to exclude subdocument that does not match some condition, we need to define the aggregate pipelines.
I assume:
zip codes are Numeric (In your example is string)
And, to exclude subdocument, we filter by `zip`
There is no any other filter
MongoDB aggregation would be:
db.person.aggregate([
{$unwind: "$address"},
{$match: {"address.zip": 12345}},
{$group: { _id: { "firstName":"$firstName", "lastName":"$lastName", _id:"$_id" }, address: { $push: "$address" } } },
{$project: {_id:0, "firstName":"$_id.firstName", "lastName":"$_id.lastName", "address": "$address"}}
])
If all filters success, we got:
[
{
"address" : [
{
"zip" : 12345
},
{
"zip" : 12345
}
],
"firstName" : "George",
"lastName" : "Washington"
}
]
Now, in Spring Data way, you need add some changes in your project:
First, find your mongo-config.xml where you need to add:
<!-- Define the mongoDbFactory with your database Name -->
<mongo:db-factory uri="mongodb://user:pass@localhost:27017/db"/>
<!-- Define the MongoTemplate -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
</bean>
MongoTemplate is the central class of the Spring’s MongoDB support providing feature sets to interact with the database. The template ... provides a mapping between your domain objects and MongoDB documents. More info
Second, in your @Service class, add following code to be loaded in @PostConstruct
@Autowired
private MongoOperations mongoOperations;
...
public List<Person> findByAddressZipCode(int zip) {
List<AggregationOperation> list = new ArrayList<AggregationOperation>();
list.add(Aggregation.unwind("address"));
list.add(Aggregation.match(Criteria.where("address.zip").is(zip)));
list.add(Aggregation.group("firstName", "lastName").push("address").as("address"));
list.add(Aggregation.project("firstName", "lastName", "address"));
TypedAggregation<Person> agg = Aggregation.newAggregation(Person.class, list);
return mongoOperations.aggregate(agg, Person.class, Person.class).getMappedResults();
}
Note: Both, Person and Address should have default empty constructor!