Spring Boot Data和MongoDB – 过滤子文档数组查询

我试图使用Spring来查询Mongo存储库并过滤数组子文档。 我已经引用了如何使用mongodb过滤子文档中的数组 ,但是想知道是否有更合适的或java结构化的方法来使用Spring。

我目前正在使用速记存储库接口表示法,但我正在使用未过滤的数组返回完整的文档。

PersonRepository.java

@Repository public interface PersonRepository extends MongoRepository  { List findByAddressZipCode(@Param("zip") int zip); } 

Person.java

 @Document public class Person { @Id private String id; private String firstName; private String lastName; private List
address; }

Address.java

 public class Address { private int zip; } 

样本输入

 { "firstName":"George", "lastName":"Washington", "address":[{ "zip":"12345" },{ "zip":"98765" },{ "zip":"12345" }] } 

预期产出

 { "firstName":"George", "lastName":"Washington", "address":[{ "zip":"12345" },{ "zip":"12345" }] } 

实际产出

 { "firstName":"George", "lastName":"Washington", "address":[{ "zip":"12345" },{ "zip":"98765" },{ "zip":"12345" }] } 

那么,在Spring Data中,这种查询并不是trivial

坏消息:
Spring Data Repository没有MongoDB Aggregation解决方案。 所以,你不能在MongoRepository中实现任何方法,比如aggregateBy...

好消息:
Spring Data提供了MongoTemplate类,允许您执行复杂查询,就像在标准MongoDB shell中一样。

因此,由于您只想exclude与某些条件不匹配的子文档,我们需要定义聚合pipelines

我假设:

 zip codes are Numeric (In your example is string) And, to exclude subdocument, we filter by `zip` There is no any other filter 

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"}} ]) 

如果所有filter都成功,我们得到:

 [ { "address" : [ { "zip" : 12345 }, { "zip" : 12345 } ], "firstName" : "George", "lastName" : "Washington" } ] 

现在,以Spring Data方式,您需要在项目中添加一些更改:

首先,找到你需要添加的mongo-config.xml

       

MongoTemplate是Spring的MongoDB支持的核心类,提供与数据库交互的function集。 模板...提供域对象MongoDB文档之间的映射。 更多信息

其次,在@Service类中,添加以下代码以加载到@PostConstruct

 @Autowired private MongoOperations mongoOperations; ... public List findByAddressZipCode(int zip) { List list = new ArrayList(); 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 agg = Aggregation.newAggregation(Person.class, list); return mongoOperations.aggregate(agg, Person.class, Person.class).getMappedResults(); } 

注意: PersonAddress都应该有默认的空构造函数!