[英]Spring Boot Data and MongoDB - Filter Subdocument Array Query
I am attempting to use Spring to Query a Mongo repository and filter an array subdocument. 我试图使用Spring来查询Mongo存储库并过滤数组子文档。 I have referenced how to filter array in subdocument with mongodb , but was wondering if there was a more appropriate or java structured method to do so using Spring.
我已经引用了如何使用mongodb过滤子文档中的数组 ,但是想知道是否有更合适的或java结构化的方法来使用Spring。
I am currently using the shorthand repository interface notation, but I am getting back the complete document with the array not filtered. 我目前正在使用速记存储库接口表示法,但我正在使用未过滤的数组返回完整的文档。
PersonRepository.java PersonRepository.java
@Repository
public interface PersonRepository extends MongoRepository <Person, String> {
List<Person> findByAddressZipCode(@Param("zip") int zip);
}
Person.java Person.java
@Document
public class Person {
@Id
private String id;
private String firstName;
private String lastName;
private List<Address> address;
}
Address.java Address.java
public class Address {
private int zip;
}
Sample Input 样本输入
{
"firstName":"George",
"lastName":"Washington",
"address":[{
"zip":"12345"
},{
"zip":"98765"
},{
"zip":"12345"
}]
}
Expected Output 预期产出
{
"firstName":"George",
"lastName":"Washington",
"address":[{
"zip":"12345"
},{
"zip":"12345"
}]
}
Actual Output 实际产出
{
"firstName":"George",
"lastName":"Washington",
"address":[{
"zip":"12345"
},{
"zip":"98765"
},{
"zip":"12345"
}]
}
Well, In Spring Data such kind of queries is not trivial
. 那么,在Spring Data中,这种查询并不
trivial
。
Bad news: 坏消息:
Spring Data Repository does not have solution for MongoDB Aggregation
. Spring Data Repository没有
MongoDB Aggregation
解决方案。 So, you cannot implement in MongoRepository any method to do so, like aggregateBy...
所以,你不能在MongoRepository中实现任何方法,比如
aggregateBy...
Good news: 好消息:
Spring Data provides MongoTemplate
class which allows you to execute complex queries, like you would do in standard MongoDB shell. Spring Data提供了
MongoTemplate
类,允许您执行复杂查询,就像在标准MongoDB shell中一样。
So, as you just want to exclude
subdocument that does not match some condition, we need to define the aggregate pipelines
. 因此,由于您只想
exclude
与某些条件不匹配的子文档,我们需要定义聚合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: MongoDB聚合将是:
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"
}
]
First, find your mongo-config.xml
where you need to add: 首先,找到你需要添加的
mongo-config.xml
:
<!-- 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. MongoTemplate
是Spring的MongoDB支持的中心类,提供与数据库交互的功能集。 The template ...
provides a mapping between your domain objects and MongoDB documents . 模板
...
提供域对象和MongoDB文档之间的映射。 More info 更多信息
Second, in your @Service
class, add following code to be loaded in @PostConstruct
其次,在
@Service
类中,添加以下代码以加载到@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! 注意:
Person
和Address
都应该有默认的空构造函数!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.