mongodb - 检索数组子集

时间:2011-06-17 14:09:14

标签: arrays mongodb mapreduce arguments subset

对于我来说,这似乎是一项简单的任务,这对我来说是个挑战。

我有以下mongodb结构:

{
(...)
"services": {
    "TCP80": {
      "data": [{
          "status": 1,
          "delay": 3.87,
          "ts": 1308056460
        },{
          "status": 1,
          "delay": 2.83,
          "ts": 1308058080
        },{
          "status": 1,
          "delay": 5.77,
          "ts": 1308060720
        }]
    }
}}

现在,以下查询返回整个文档:

{ 'services.TCP80.data.ts':{$gt:1308067020} }

我想知道 - 我是否可以只接收符合$ gt条件的那些“数据”数组条目(缩小文档的种类)?

我正在考虑MapReduce,但是找不到一个关于如何将外部参数(timestamp)传递给Map()函数的示例。 (此功能已添加到1.1.4 https://jira.mongodb.org/browse/SERVER-401

此外,总有一种替代方法可以编写storedJs函数,但由于我们说的是大量数据,因此这里不能容忍db-locks。

我很可能需要将结构重新设计为1级深度,例如:

{
   status:1,delay:3.87,ts:138056460,service:TCP80
},{
   status:1,delay:2.83,ts:1308058080,service:TCP80
},{
   status:1,delay:5.77,ts:1308060720,service:TCP80
}

但是DB会大幅增长,因为“服务”只是附加每个文档的众多选项之一。

请咨询!

提前致谢

4 个答案:

答案 0 :(得分:2)

在带有聚合框架的2.1版中,您现在可以执行此操作:

1: db.test.aggregate(
2:   {$match : {}},
3:   {$unwind: "$services.TCP80.data"},
4:   {$match: {"services.TCP80.data.ts": {$gte: 1308060720}}}
5: );

您可以使用第2行中的自定义条件来过滤父文档。如果您不想过滤它们,只需将第2行留下即可。

答案 1 :(得分:1)

目前不支持此功能。默认情况下,除非使用字段限制或$ slice运算符,否则将始终接收整个文档/数组。目前,这些工具不允许根据搜索条件过滤数组元素。

您应该观看此请求以获取此方法:https://jira.mongodb.org/browse/SERVER-828

答案 2 :(得分:0)

我正在尝试做类似的事情。我尝试过使用GROUP函数的建议,但是我无法将嵌入的文档分开或者做错了。

我需要按ID提取/获取嵌入文档的子集。以下是我使用Map / Reduce进行的方式:

db.parent.mapReduce(
  function(parent_id, child_ids){
    if(this._id == parent_id) 
      emit(this._id, {children: this.children, ids: child_ids})
  }, 
  function(key, values){
    var toReturn = [];

    values[0].children.forEach(function(child){
      if(values[0].ids.indexOf(product._id.toString()) != -1)
        toReturn.push(child);
    });
    return {children: toReturn};
  }, 
  { 
     mapparams: [
       "4d93b112c68c993eae000001", //example parent id
       ["4d97963ec68c99528d000007", "4debbfd5c68c991bba000014"] //example embedded children ids
     ]
  }
).find()

我已将我的收藏名称抽象为“父级”,并将其嵌入的文档抽象为“子级”。我传入两个参数:父文档ID和我想从父级检索的嵌入式文档ID的数组。这些参数作为第三个参数传递给mapReduce函数。

在map函数中,我在集合中找到父文档(我很确定使用_id索引)并将其id和子元素发送到reduce函数。

在reduce函数中,我获取传入的文档并遍历每个子节点,收集具有所需ID的子节点。循环遍历所有孩子并不理想,但我不知道在嵌入式文档中通过ID查找的另一种方法。

我还假设在reduce函数中,因为我在ID搜索时只发出了一个文档。如果您希望匹配多个parent_id,则必须循环使用reduce函数中的values数组。

我希望这可以帮助那里的人,因为我在谷歌搜索没有任何结果。希望很快我们会看到MongoDB的内置功能,但在此之前我必须使用它。

答案 3 :(得分:0)

Fadi,至于“将嵌入式文件分开” - 小组应该处理这个没有问题

function getServiceData(collection, criteria) {

    var res=db[collection].group({
        cond: criteria,
        initial: {vals:[],globalVar:0},
        reduce: function(doc, out) {
            if (out.globalVar%2==0)
                out.vals.push({doc.whatever.kind.and.depth);
                out.globalVar++;
        },
        finalize: function(out) {
            if (vals.length==0)
                out.vals='sorry, no data';
            return out.vals;
        }
    });

    return res[0];
};