2015-11-13 70 views
4

,我是新来的MongoDB和需要完成我的任务帮助嵌入式阵列元素的数量:查找文件由符合条件

我使用MongoDB的查询为拍摄一个人就是行动。该行动是嵌入在个人文档中是这样的:

{ 
    "_id" : ObjectId("56447ac0583d4871570041c3"), 
    "email" : "[email protected]", 
    "actions" : [ 
     { 
      "name" : "support", 
      "created_at" : ISODate("2015-10-17T01:40:35.000Z"), 
     }, 
     { 
      "name" : "hide", 
      "created_at" : ISODate("2015-10-16T01:40:35.000Z") 
     }, 
     { 
      "name" : "support", 
      "created_at" : ISODate("2015-10-17T03:40:35.000Z"), 
     } 
    ] 
} 

一个人可以有不同的动作名(supporthide仅有2例)的许多行动。

我知道,我能找到的所有的人至少有一个support动作是这样的:

db.test.find({'actions.name':'support'}) 

我想要做的,就是检索所有的人至少有X support行动。这可能不使用JavaScript语法?随着人们可能有数百个动作,这将是缓慢的。

所以,如果我想至少有2个support行动的所有人,我所知道的唯一的方法就是使用js的语法:

db.test.find({$where: function() { 
    return this.actions.filter(function(action){ 
    return action.name = 'support'; 
    }).length >= 2; 
}}); 

是否有其他/更好/更快此查询的可能性?

回答

2

那么做到这一点的最好办法是使用的.aggregate()方法可用于访问聚集管道。

可以减少文件大小使用$match运营商过滤掉不符合给定条件的所有文档的流水线处理。

您需要使用$redact运算符仅返回文档中阵列中名称为“支持”的元素数为$gte2。这里的$map操作返回匹配你的性判据和假,你可以轻松地拖放使用$setDifference运算符子文档的数组。当然,操作者$size返回该数组的大小。

db.test.aggregate([ 
    { "$match": { 
     "actions.name": "support", 
     "actions.2": { "$exists": true } 
    }}, 
    { "$redact": { 
     "$cond": [ 
      { "$gte": [ 
       { "$size": { 
        "$setDifference": [ 
         { "$map": { 
          "input": "$actions", 
          "as": "action", 
          "in": { 
           "$cond": [ 
            { "$eq": [ "$$action.name", "support" ] }, 
            "$$action", 
            false 
           ] 
          } 
         }}, 
         [false] 
        ] 
       }}, 
       2 
      ]}, 
      "$$KEEP", 
      "$$PRUNE" 
     ] 
    }} 
]) 

从MongoDB的3.2这可以通过使用操作者$filter处理。

db.test.aggregate([ 
    { "$match": { 
     "actions.name": "support", 
     "actions.2": { "$exists": true } 
    }}, 
    { "$redact": { 
     "$cond": [ 
      { "$gte": [ 
       { "$size": { 
        "$filter": { 
         "input": "$actions", 
         "as": "action", 
         "cond": { "$eq": [ "$$action.name", "support" ] } 
        } 
       }}, 
       2 
      ]}, 
      "$$KEEP", 
      "$$PRUNE" 
     ] 
    }} 
]) 

正如@BlakesSeven指出:

$setDifference是细只要被过滤的数据为 “唯一”。在这种情况下,它“应该”没问题,但是如果任何两个结果包含相同的日期,那么通过将这两个结果视为一个结果会导致结果偏离。 $filter是最好的选择,但如果数据不是唯一的,那么目前需要$放松。

-2

我没有这个基准对你的尝试,但是这听起来像蒙戈的聚合框架很大的用例。

db.test.aggregate([ 
{$unwind: "$actions"}, 
{$group: { 
    _id: { _id: "$_id", action: "$actions}, 
    count: {$sum: 1} 
}, 
{$match: {$and: [{count: {$gt: 2}}, {"_id.action": "support"]} 
]); 

请注意,我没有运行在mongo中,所以它可能有一些语法问题。

它背后的理念是:

  1. unwind动作阵列,该阵列中的每个元素变成它自己的文件
  2. group由_id结果集合 - 动作型对,算多少,我们获得每一个。
  3. match将过滤的唯一的东西,我们有兴趣。
+0

不,这不是OP想要的。 – styvane

+0

@ user3100115你为什么认为它不是OP想要的? –

+0

运行他的查询并将结果与​​您的结果进行比较,然后您将理解“为什么”。另外问题是非常明确 – styvane