2016-07-05 110 views
2

鑑於我的配置文件數據如下所示,我想查找用戶名和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聚合管道進行投影設置。

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

另請參見morphia船員在88行圍繞https://github.com/mongodb/morphia/blob/master/morphia/src/test/java/org/mongodb/morphia/aggregation/AggregationTest.java寫的示例。

相關問題