春天引导数据和MongoDB - 过滤子文档阵查询 [英] Spring Boot Data and MongoDB - Filter Subdocument Array Query

查看:829
本文介绍了春天引导数据和MongoDB - 过滤子文档阵查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用Spring来查询蒙戈库和过滤器阵列子文档。我曾经引用<一个href=\"http://stackoverflow.com/questions/15117030/how-to-filter-array-in-subdocument-with-mongodb/\">how在MongoDB中子文档过滤​​阵列,但不知道是否有这样做使用Spring更合适或Java结构的方法。

我目前使用速记库接口符号,但我正在逐渐回来不过滤阵列的完整的文档。

PersonRepository.java

  @Repository
公共接口PersonRepository扩展MongoRepository&LT;人,字符串&GT; {
    清单&LT;&人GT; findByAddressZip code(@Param(ZIP)INT ZIP);
}

Person.java

  @Document
公共类Person {
    @ID
    私人字符串ID;    私有String的firstName;
    私人字符串的lastName;
    私人列表&LT;地址&gt;地址;
}

Address.java

 公共类地址{
    私人诠释拉链;
}

采样输入

  {
 名字:乔治,
 姓氏:华盛顿号,
 地址:[{
     拉链:12345
  },{
     拉链:98765
  },{
     拉链:12345
  }]
}

预计输出

  {
 名字:乔治,
 姓氏:华盛顿号,
 地址:[{
     拉链:12345
  },{
     拉链:12345
  }]
}

实际输出

  {
 名字:乔治,
 姓氏:华盛顿号,
 地址:[{
     拉链:12345
  },{
     拉链:98765
  },{
     拉链:12345
  }]
}


解决方案

那么,在春天这样的数据类型的查询是不是琐碎

坏消息:

春数据仓库不具备 MongoDB的聚合解决方案。所以,你不能在MongoRepository实施任何方法来做,如 aggregateBy ...

好消息:

春天的数据提供了 MongoTemplate 类,它可以让你执行复杂查询,就像你在MongoDB的标准做外壳

所以,你只是想排除子文档不符合某些条件下,我们需要定义的总管道

我假设:

 拉链codeS是数字(在您的例子是字符串)
而且,以排除子文档中,我们通过`zip`过滤
有没有任何其他的过滤器

MongoDB的聚集将是:

  db.person.aggregate([
    {$放松:$地址},
    {$匹配:{address.zip:12345}},
    {$组:{_id:{名字:$名字,姓氏:$姓氏,_id:$ _ ID},地址:{$推:$地址}}},
    {$项目:{_id:0,名字:$ _ id.firstName,姓氏:$ _ id.lastName,地址:$地址}}
])

如果全部过滤器的成功,我们得到了:

  [
    {
        地址 : [
            {
                拉链:12345
            },
            {
                拉链:12345
            }
        ]
        名字:乔治,
        姓氏:华盛顿
    }
]



现在,在Spring数据的方式,你需要在你的项目中添加一些变化:

首先,找到你的蒙戈-config.xml中,你需要添加:

 &LT;! - 与您的数据库名称定义mongoDbFactory  - &GT;
&LT;蒙戈:DB-URI工厂=的MongoDB://用户:通@本地:27017 / DB/&GT;&LT;! - 定义MongoTemplate - &GT;
&LT;豆的id =mongoTemplate级=org.springframework.data.mongodb.core.MongoTemplate&GT;
    &LT;构造带参数的名称=mongoDbFactoryREF =mongoDbFactory/&GT;
&LT; /豆&GT;

MongoTemplate 是中央级的Spring的MongoDB的支持,提供功能设置为与数据库进行交互。模板 ... 提供的 MongoDB的文档您的域对象之间的映射更多信息

二,在你的 @Service 类中添加以下code在 @PostConstruct <加载/ p>

  @Autowired
私人MongoOperations mongoOperations;...公开名单&LT;&人GT; findByAddressZip code(INT ZIP){    清单&LT; AggregationOperation&GT;名单=新的ArrayList&LT; AggregationOperation&GT;();
    list.add(Aggregation.unwind(地址));
    list.add(Aggregation.match(Criteria.where(address.zip)是(ZIP)));
    list.add(Aggregation.group(名字,姓氏)推(地址)作为(地址)。);
    list.add(Aggregation.project(名字,姓氏,地址));
    TypedAggregation&LT;&人GT; AGG = Aggregation.newAggregation(Person.class,清单);
    返回mongoOperations.aggregate(总比分,Person.class,Person.class).getMappedResults();
}

注意:两个地址应具有默认为空的构造<! / p>

I am attempting to use Spring to Query a Mongo repository and filter an array subdocument. 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.

I am currently using the shorthand repository interface notation, but I am getting back the complete document with the array not filtered.

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;
}

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.

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!

这篇关于春天引导数据和MongoDB - 过滤子文档阵查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆