복붙노트

[SPRING] 배열에서 일치하는 요소를 봄 mongodb에서 검색하는 방법은 무엇입니까?

SPRING

배열에서 일치하는 요소를 봄 mongodb에서 검색하는 방법은 무엇입니까?

나는 특정 '_id'가있는 문서와 다른 '_id'가있는 단일 임베디드 문서를 검색하려고합니다.

내 문서는 카탈로그를 나타내며 일련의 코스를 포함합니다.

예제 데이터 :

'_id': ObjectId('1111'),
'name': 'example catalog',
...
...
'courses': [
     { 
         '_id': ObjectId('2222'),
         'name': 'my course',
         ...
     },
     {
         ....
     }

mongodb에서이 집계 쿼리를 실행하고 원하는 것을 다시 얻습니다.

db.getCollection('catalogs').aggregate(
{ $match: { '_id': ObjectId('58e8da206ca4f710bab6ef74') } },
{ $unwind: '$courses' },
{ $match: { 'courses._id': ObjectId('58d65541495c851c1703c57f') } })

앞서 언급했듯이 하나의 코스 인스턴스가 포함 된 단일 카탈로그 인스턴스를 다시 가져 왔습니다.

내 자바 저장소에서 동일한 작업을 수행하려고했습니다.

    Aggregation aggregation = Aggregation.newAggregation(
            Aggregation.match(Criteria.where(Catalog.ID_FIELD).is(catalogId)),
            Aggregation.unwind(Catalog.COURSES_FIELD, true),
            Aggregation.match(Criteria.where(Catalog.COURSES_FIELD + '.' + Course.ID_FIELD).is(embeddedCourseId))
    );
    AggregationResults<Catalog> results = mongoTemplate.aggregate(aggregation,
            Catalog.class, Catalog.class);

    List<Catalog> catalog  = results.getMappedResults();

그러나 불행하게도, 빈 코스 배열을 가진 '예제 카탈로그'의 인스턴스가 있습니다.

디버깅하는 동안, 나는 그 결과 안에, 돌아 오는 두 가지 소품이 있다는 것을 발견했다. 첫 번째는 mappedResults (mongoDB에서 반환 된 변환 된 객체를 나타냄)라는 사용 된 것입니다. 빈 코스 배열을 포함합니다. 다른 하나는 rawResults입니다 (데이터를 DBObject로 나타냄).

내 Catalog 클래스에는 ArrayList가 포함됩니다 (차이가있는 경우).

도움을 요청하고 결과를 올바르게 변환하기 위해 내가해야 할 일을 알려주십시오.

해결법

  1. ==============================

    1.아래 옵션을 시도해보십시오. 핵심은 응답을 매핑 할 때 구조를 보존하는 것입니다.

    아래 옵션을 시도해보십시오. 핵심은 응답을 매핑 할 때 구조를 보존하는 것입니다.

    일반 검색어 :

    $ 위치 투영 사용

    Query query = new Query();
    query.addCriteria(Criteria.where("id").is(new ObjectId("58e8da206ca4f710bab6ef74")).and("courses.id").is(new ObjectId("58d65541495c851c1703c57f")));
    query.fields().include("name").position("courses", 1);
    List<Course> courses = mongoTemplate.find(query, Course.class);
    

    $ elemMatch 프로젝션 사용하기

    Query query = new Query();
    query.addCriteria(Criteria.where("id").is(new ObjectId("58e8da206ca4f710bab6ef74")));
    query.fields().include("name").elemMatch("courses", Criteria.where("_id").is(new ObjectId("58d65541495c851c1703c57f") ) );
    List<Course> Course = mongoTemplate.find(query, Course.class);
    

    집합

    Mongo 버전> 3.4 및 Spring 1.5.2 Boot / Spring 1.10.1 Mongo.

    기존의 모든 속성을 유지하면서 courses 필드를 $ filter 값으로 덮어 쓰는 $ addFields stage를 사용할 수 있습니다. 현재 스프링 버전에서는 addFields 빌더를 찾을 수 없습니다. 따라서 AggregationOperation을 사용하여 새 AggregationOperation을 만들어야합니다.

    AggregationOperation addFields = new AggregationOperation() {
        @Override
        public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) {
            DBObject dbObject =
                    new BasicDBObject("courses",
                            new BasicDBObject("$filter",
                                    new BasicDBObject("input", "$$courses").
                                            append("as", "course").
                                            append("cond",
                                                new BasicDBObject("$eq", Arrays.<Object>asList("$$course._id", new ObjectId("58d65541495c851c1703c57f"))))));
            return new BasicDBObject("$addFields", dbObject);
        }
    };
    
    Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(Criteria.where("_id").is(new ObjectId("58e8da206ca4f710bab6ef74"))),
                addFields
     );
    

    Mongo 버전 3.2 및 Spring 1.5.2 Boot / Spring 1.10.1 Mongo ..

    아이디어는 위와 동일하지만이 파이프 라인은 $ project를 사용하므로 최종 응답을 유지하려는 모든 필드를 추가해야합니다. $ filter 파이프 라인을 생성하기 위해 스프링 도우미 메서드를 사용했습니다.

    Aggregation aggregation = newAggregation(
         Aggregation.match(Criteria.where("id").is(new ObjectId("58e8da206ca4f710bab6ef74"))),
         Aggregation.project("name")
                     .and(ArrayOperators.Filter.filter("courses").as("course")                          
                     .by(ComparisonOperators.Eq.valueOf("course._id").equalToValue(new ObjectId("58d65541495c851c1703c57f")))
                        ).as("courses")
     );
    

    Mongodb 버전 <= 2.6

    $ unwind를 사용하고 코스 필드를 추가하여 스프링 맵핑을 올바르게 수행해야합니다.

  2. ==============================

    2.여기에있는 문제는 Catalog 클래스에 List / ArrayList에 매핑되는 courses 필드가 있다는 것입니다. 그러나 집계 쿼리가 코스 배열을 푸는 경우 코스 필드를 하위 문서로 출력합니다. Spring 매퍼는 Catalog 객체 구조와 일치하지 않기 때문에이를 처리하는 방법을 모른다.

    여기에있는 문제는 Catalog 클래스에 List / ArrayList에 매핑되는 courses 필드가 있다는 것입니다. 그러나 집계 쿼리가 코스 배열을 푸는 경우 코스 필드를 하위 문서로 출력합니다. Spring 매퍼는 Catalog 객체 구조와 일치하지 않기 때문에이를 처리하는 방법을 모른다.

    여기에서 문제를 완전히 정의하지는 못했지만 집합체가 Catalog 객체가 아닌 Course 객체를 반환했다면 아마 더 이해할 수있을 것입니다. 이를 수행하려면 결과가 단일 Course 객체와 정확히 같아 지도록 집계 파이프 라인에 프로젝션 스테이지를 추가해야합니다. 핵심은 MongoDB에서 되돌아 오는 데이터가 객체 구조와 일치해야한다는 것입니다.

  3. from https://stackoverflow.com/questions/43326515/how-to-retrieve-matching-element-in-array-in-spring-mongodb by cc-by-sa and MIT license