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

5
我正在尝试使用Spring查询Mongo存储库并过滤数组子文档。我已经参考了如何使用mongodb过滤子文档中的数组,但想知道是否有更适合的Java结构化方法来使用Spring进行过滤。
我目前正在使用简写存储库接口符号,但返回的是未过滤的完整文档。
PersonRepository.java
@Repository
public interface PersonRepository extends MongoRepository <Person, String> {
    List<Person> 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;
}

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"
  }]
}
1个回答

7

好的,在Spring Data中,这种类型的查询并不是简单的。

不好的消息:
Spring Data Repository没有MongoDB Aggregation的解决方案。因此,您不能在MongoRepository中实现任何方法来执行此操作,如aggregateBy...

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

因此,由于您只想排除不符合某些条件的子文档,我们需要定义聚合管道

我假设:

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

如果所有过滤器都成功,我们将得到:
[ 
    {
        "address" : [ 
            {
                "zip" : 12345
            }, 
            {
                "zip" : 12345
            }
        ],
        "firstName" : "George",
        "lastName" : "Washington"
    }
]


现在,在Spring Data中,您需要对项目进行一些更改:

首先,找到您的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>
是Spring的MongoDB支持的核心类,提供与数据库交互的功能集。该模板提供了域对象MongoDB文档之间的映射。 更多信息 其次,在您的@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();
}

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


非常感谢您,Valijon。这对我的用例非常有效,并且我认为聚合是最合适的方法。您是否有任何其他建议,以便使用更易读的方法或使用其他框架而不需要广泛了解mongo shell语言? - Eagles5iveBC
Spring Data是目前最“易读”的框架。它非常适用于像在MongoRepository中定义方法这样的简单“查询”。它可以将MongoDB文档“自动”映射到您的POJO类。此外,它还提供了QueryDSL查询构建器(用于聚合、更复杂的查询)。其他框架,如原生的MongoDB驱动程序需要广泛的知识作为shell命令行。在我们的项目中,我们使用Spring Data进行MongoDB查询。 - Valijon
非常感谢您,Valijon。这非常有帮助。 - Eagles5iveBC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接