【问题标题】:Spring Boot Data and MongoDB - Filter Subdocument Array QuerySpring Boot 数据和 MongoDB - 过滤子文档数组查询
【发布时间】:2016-04-17 13:13:37
【问题描述】:

我正在尝试使用 Spring 来查询 Mongo 存储库并过滤数组子文档。我已经引用了how to filter array in subdocument with 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"
  }]
}

【问题讨论】:

    标签: java arrays spring mongodb


    【解决方案1】:

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

    如果所有过滤器都成功,我们得到:

    [ 
        {
            "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>
    

    MongoTemplate 是 Spring 的 MongoDB 支持的中心类,提供与数据库交互的功能集。模板... 提供您的域对象MongoDB 文档 之间的映射。 More info

    其次,在您的@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 语言知识的附加框架,您有任何其他建议吗?
    • 嗯,Spring Data 是当今最“可读”的框架。它对于简单的“查询”非常有用,例如在 MongoRepository 中定义方法。它将“自动”MongoDB 文档映射到您的 POJO 类。此外,提供 QueryDSL 查询生成器(用于聚合,更复杂的查询)。其他框架,如原生 MongoDB 驱动程序,需要广泛的 shell 命令行知识。在我们的项目中,我们使用 Spring Data 进行 MongoDB 查询。
    • 非常感谢 Valijon。这很有帮助
    猜你喜欢
    • 1970-01-01
    • 2016-09-29
    • 1970-01-01
    • 2018-01-26
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 2019-06-25
    相关资源
    最近更新 更多