2016-07-05 5 views
2

내 프로필 데이터가 아래처럼 보이면 userName과 productId의 조합에 대한 프로필을 으로 찾고이 제품에 대한 해당 계약의 프로필 만 반환하고 싶습니다.morphia로 mongo 문서에 임베디드 배열을 필터링하는 방법

{ 
    "firstName": "John", 
    "lastName": "Doe", 
    "userName": "[email protected]", 
    "language": "NL", 
    "timeZone": "Europe/Amsterdam", 
    "contracts": [ 
     { 
      "contractId": "DEMO1-CONTRACT", 
      "productId": "ticket-api", 
      "startDate": ISODate('2016-06-29T09:06:42.391Z'), 
      "roles": [ 
       { 
        "name": "Manager", 
        "permissions": [ 
         { 
          "activity": "ticket", 
          "permission": "createTicket" 
         }, 
         { 
          "activity": "ticket", 
          "permission": "updateTicket" 
         }, 
         { 
          "activity": "ticket", 
          "permission": "closeTicket" 
         } 
        ] 
       } 
      ] 
     }, 
     { 
      "contractId": "DEMO2-CONTRACT", 
      "productId": "comment-api", 
      "startDate": ISODate('2016-06-29T10:27:45.899Z'), 
      "roles": [ 
       { 
        "name": "Manager", 
        "permissions": [ 
         { 
          "activity": "comment", 
          "permission": "createComment" 
         }, 
         { 
          "activity": "comment", 
          "permission": "updateComment" 
         }, 
         { 
          "activity": "comment", 
          "permission": "deleteComment" 
         } 
        ] 
       } 
      ] 
     } 
    ] 
}  

해결 방법은 명령 줄에서 찾을 수 있습니다. 그러나 Morphia (최신 버전)를 사용하여이를 수행하는 방법을 찾는 것 같지 않습니다.

db.Profile.aggregate([ 
    { $match: {"userName": "[email protected]"}}, 
    { $project: { 
     contracts: {$filter: { 
      input: '$contracts', 
      as: 'contract', 
      cond: {$eq: ['$$contract.productId', "ticket-api"]} 
     }} 
    }} 
]) 

이것은 내가 지금까지 가지고있는 것입니다. 어떤 도움을 가장 사이에 나는 집계 파이프 라인을 사용하지 않는 다른 해결책을 발견 ...

Query<Profile> matchQuery = getDatastore().createQuery(Profile.class).field(Profile._userName).equal(userName); 
getDatastore() 
    .createAggregation(Profile.class) 
    .match(matchQuery) 
    .project(Projection.expression(??)) 

참고 감사합니다.

public Optional<Profile> findByUserNameAndContractQuery(String userName, String productId) { 
     DBObject contractQuery = BasicDBObjectBuilder.start(Contract._productId, productId).get(); 
     Query<Profile> query = 
       getDatastore() 
         .createQuery(Profile.class) 
         .field(Profile._userName).equal(userName) 
         .filter(Profile._contracts + " elem", contractQuery) 
         .retrievedFields(true, Profile._contracts + ".$"); 
     return Optional.ofNullable(query.get()); 
    } 

답변

0

필자는 최종적으로 배열에서 최대 1 개 요소 만 반환하려는 가정하에 최단 경로를 찾았습니다.

db.Profile.aggregate([ 
    { $match: {"userName": "[email protected]"}}, 
    { $unwind: "$contracts"}, 
    { $match: {"contracts.productId": "comment-api"}} 
]) 
0

첫 번째 디자인에 따라 일치 시키려면 morphia aggregation 파이프 라인을 사용하여 프로젝션 설정을 시도 할 수 있습니다.

Query<Profile> matchQuery = getDatastore().createQuery(Profile.class).field(Profile._userName).equal(userName); 

getDatastore() 
.createAggregation(Profile.class) 
.match(matchQuery) 
.project(Projection.expression("$filter", new BasicDBObject() 
     .append("input", "$contracts") 
     .append("as", "contract") 
     .append("cond", new BasicDBObject() 
      .append("$eq", Arrays.asList('$$contract.productId', "ticket-api"))); 

또한 https://github.com/mongodb/morphia/blob/master/morphia/src/test/java/org/mongodb/morphia/aggregation/AggregationTest.java에서 라인 (88) 주위 모르핀 승무원에 의해 작성된 예를 참조.