복붙노트

[SPRING] 스프링 부트 데이터와 MongoDB - 서브 디렉토리 배열 쿼리 필터링

SPRING

스프링 부트 데이터와 MongoDB - 서브 디렉토리 배열 쿼리 필터링

Spring을 사용하여 Mongo 저장소를 쿼리하고 배열 하위 문서를 필터링하려고합니다. 나는 어떻게 mongodb와 하위 문서의 배열을 필터링하는 방법을 참조했지만 더 적절한 또는 Java 구조화 된 메서드를 사용하여 그렇게 봄 궁금 해서요.

현재 속기 저장소 인터페이스 표기법을 사용하고 있지만 필터링되지 않은 배열로 전체 문서를 다시 가져옵니다.

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. ==============================

    1.글쎄, 봄 데이터에서 그런 종류의 쿼리는 사소하지 않습니다.

    글쎄, 봄 데이터에서 그런 종류의 쿼리는 사소하지 않습니다.

    나쁜 소식: 스프링 데이터 저장소는 MongoDB 집계를위한 솔루션을 가지고 있지 않습니다. 그래서, aggregateBy와 같이 MongoRepository에서 그렇게 할 수있는 방법을 구현할 수 없습니다 ...

    좋은 소식: Spring Data는 MongoTemplate 클래스를 제공하여 표준 MongoDB 셸에서와 같이 복잡한 쿼리를 실행할 수 있습니다.

    따라서 일부 조건과 일치하지 않는 하위 문서를 제외하려는 경우 집계 파이프 라인을 정의해야합니다.

    나는 다음과 같이 가정한다.

    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 문서 간의 매핑을 제공합니다. 더 많은 정보

    둘째, @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();
    }
    

    주 : Person과 Address 모두 기본 빈 생성자를 가져야합니다!

  2. from https://stackoverflow.com/questions/34751845/spring-boot-data-and-mongodb-filter-subdocument-array-query by cc-by-sa and MIT license