2016-07-05 107 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写的示例。

相关问题