2016-07-05 3 views
2

私のプロファイルデータは以下のようになります。私はuserNameとproductIdの組み合わせのプロファイルを見つけて とし、この製品のそれぞれの契約のプロファイルのみを返します。モンゴー文書で埋め込み配列をフィルタリングする方法

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

最初のデザインに合わせるには、モルフィア集約パイプラインを使用して投影設定を試すことができます。

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"))); 

さらに、モーフアクルーが88行目でhttps://github.com/mongodb/morphia/blob/master/morphia/src/test/java/org/mongodb/morphia/aggregation/AggregationTest.javaに書いた例を参照してください。

関連する問題