Mongodb聚合具有非常复杂的文档

时间:2014-02-10 22:55:37

标签: mongodb aggregation-framework

我有一个相当复杂的文档模型,其结构如下:

{
   _id: 1,
   "title": "I'm number one",
   ... (many other meta data text fields not desired in the summary)
   "foo": {
      "tom":   [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
      "dick":  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
      "harry": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
      ... (Total of 14 fields in foo)
   },
   "bar": {
      "joe":   [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
      "fred":  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
      "bob":   [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
      ...  (Total of 14 fields in bar)
   },
   "dodads": [
      {
         "contraption": 0,
         "doohickey": 0,
         "gewgaw": 0,
         "gizmo": 0,
         ... (total of 15 elements in each doodad object)
      },
      {
         "contraption": 0,
         "doohickey": 0,
         "gewgaw": 0,
         "gizmo": 0,
         ...
      },
      ... (total of 6 objects in dodads object array)
   ]
},
... (a couple hundred documents in total)

我正在寻找的是具有数字数据的所有对象/数组的摘要。我希望结果是原始格式的文档,其中包含汇总的数字字段。现在,让我们说文件都具有相同的结构。

聚合结果如下所示

{
   "foo": {
      "tom":   [35, 65, 13, 22, 36, 58, 93, 43, 56, 44, 23, 72],
      "dick":  [56, 87, 28, 49, 34, 22, 48, 86, 29, 23, 88, 29],
      ... (All 14 fields in foo)
   },
   "bar": {
      "joe":   [87, 28, 49, 34, 22, 48, 86, 29, 23, 88, 29, 47],
      "fred":  [13, 22, 36, 58, 93, 43, 56, 44, 23, 72, 35, 65],
      ...  (All 14 fields in bar)
   },
   "dodads": [
      {
         "contraption": 45,
         "doohickey": 88,
         "gewgaw": 23,
         "gizmo": 64,
         ... (All 15 elements in each doodad object)
      },
      {
         "contraption": 12,
         "doohickey": 73,
         "gewgaw": 57,
         "gizmo": 86,
         ...
      },
      ... (All 6 objects in dodads object array)
   ]
}

我相信我可以展开数组,指定总和和投影,并通过广泛而详细的聚合管道获得我想要的内容。我也可以做多个查询抓取组件(一个只是foo,第二个只是吧......)。

我想知道的是,是否有指定摘要的简便方法?例如,我可以说我想要foofoo.tom的摘要并将其内容汇总回来吗?

1 个答案:

答案 0 :(得分:0)

您的文档结构中有些内容实际上无法帮助您。这主要是使用像这样的子文档:

"foo": {
   "tom":   [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
   "dick":  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
   "harry": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
},
"bar": {
   "joe":   [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
   "fred":  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
   "bob":   [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
}

这使事情变得非常困难,因为你通常只能获取所包含的字段,例如“foo.tom”,“bar.fred”等。出于我之前评论过的原因,通过links进行最佳解释,但总结一下,在可能的情况下,您可以通过更改文档的结构来简化生活:

"foo": [
   { "name": "tom", "values": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] },
   { "name": "dick", "values": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] },
   { "name": "harry", "values": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] }
],

因为这将使您更好地查询元素,而不是显式引用,否则您将需要使用它们。我之前给出的答案更深入地探讨了这一点。

至于您在查找数字字段时要执行的操作,I asked this question here基本上是对所需内容的重写。从响应开始,使用mapReduce进行方法

map = function() {
    function isNumber(n) {
      return !isNaN(parseFloat(n)) && isFinite(n);
    }

    var numerics = [];
    for(var fn in this) {
        if (isNumber(this[fn])) {
            numerics.push({f: fn, v: this[fn]});
        }
        if (Array.isArray(this[fn])) {
            // example ... more complex logic needed
            if(isNumber(this[fn][0])) {
                numerics.push({f: fn, v: this[fn]});
            }
        }
    }
    emit(this._id, { n: numerics });
};

reduce = function(key, values) {
  return values;  
};

这可能是你需要的,但是从这个框架中要注意你可能需要对文档中的字段进行一些复杂的展开才能测试它,因为实际上没有简单的方法可以做到这一点。您基本上必须在其中添加许多遍历逻辑,以便在您拥有的结构中提供您想要的内容。

正如您在“查找有关文档结构的信息”之后,您可能希望查看此问题的答案: MongoDB Get names of all keys in collection