聚合以按大小创建文档组

时间:2016-04-13 19:43:32

标签: javascript mongodb mapreduce mongodb-query aggregation-framework

我有一个名为" orders"的集合。此集合中的每个订单都有一系列产品ID。例如:

> db.orders.find()
[
  { _id: 1, products: [10, 11, 12] },
  { _id: 2, products: [13, 14] },
  { _id: 3, products: [15] },
  { _id: 4, products: [16, 17] }
]

现在,我想创建一个集合,我将n个产品组合在一起,每个订单的产品必须在同一个文档中,并且n总是大于产品的数量任何订单。

所以,在上面的示例中,假设我将n指定为3.结果如下:

[{
  orders: [1],
  products: [10, 11, 12]
}, {
  orders: [2, 3],
  products: [13, 14, 15]
}, {
  orders: [4],
  products: [16, 17]
}]

mongo聚合可以实现吗?

1 个答案:

答案 0 :(得分:1)

这实际上并不是你在数组聚合过程中会做的事情。由于您需要跨文档维护值,因此在聚合框架中无法实现。除了"引爆点之外没有自然的分组边界"其中"products"的总收集元素变为三个或更多值,并且这种累积需要"全局",这是聚合框架无法使用的内容

MapReduce有&#34;全局&#34;,但是当你考虑所涉及的操作时,这并不会减少&#34;任何东西。当然有&#34;积累&#34;,但这只是处理到那个&#34;临界点&#34;的总数据的一个因素。正如刚才提到的。返回的实际数据是&#34;与集合中存储的数据完全相同的<#34; ,但只是以输出格式重新组织

因此,最好在处理光标&#34;时处理文档中的累积。因此,使用更多项目扩展您的示例数据以说明另一点:

{ "_id" : 1, "products" : [ 10, 11, 12 ] }
{ "_id" : 2, "products" : [ 13, 14 ] }
{ "_id" : 3, "products" : [ 15 ] }
{ "_id" : 4, "products" : [ 16, 17 ] }
{ "_id" : 5, "products" : [ 18, 19 ] }
{ "_id" : 6, "products" : [ 20, 21 ] }
{ "_id" : 7, "products" : [ 22, 23 ] }

然后你基本上处理&#34;光标&#34;结果与逻辑做累积:

var output = {}

db.orders.find().forEach(function(order) {
  if ( !output.hasOwnProperty("_id") ) {
    output = { "_id": [order._id], products: [] };
  } else {
    output._id = output._id.concat([order._id]);
  }
  output.products = output.products.concat(order.products);

  if ( output.products.length > 3 ) {
    var hold = {};
    hold._id = output._id.slice(-1);
    hold.products = output.products.slice(-(output.products.length-3));
    output.products = output.products.slice(0,3);
    printjson(output);
    output = hold;
  } else if ( output.products.length == 3) {
    printjson(output)
    output = {};
  }
})

if ( Object.keys(output).length != 0 ) {
  printjson(output);
}

输出为:

{ "_id" : [ 1 ], "products" : [ 10, 11, 12 ] }
{ "_id" : [ 2, 3 ], "products" : [ 13, 14, 15 ] }
{ "_id" : [ 4, 5 ], "products" : [ 16, 17, 18 ] }
{ "_id" : [ 5, 6 ], "products" : [ 19, 20, 21 ] }
{ "_id" : [ 7 ], "products" : [ 22, 23 ] }

因此输出采用不同的格式&#34;并且&#34;累积&#34;这样所有"products"数据最多只有三个项目,但实际上它仍然是集合中的相同数据,没有减少 。这是重要的一点。

因此,累积过程需要&#34; global&#34; ,您可以在其中构建累积的_id值列表以及总计products 。另请注意,由于为[4,5]累积的数据实际上会超过三个项目,因此剩余的项目将被转移到下一个&#34;分组&#34;中。

现在mapReduce确实有如前所述的&#34; globals&#34; ,但这种文档的累积意味着通常将遗留下来的东西没有&#34;发出&#34;因为总"products"尚未达到 3 的计数。

mapReduce的情况实际上只是作为服务器上的 JavaScript runnner ,因为这个累积实际上是在&#34; mapper&#34;功能而不是&#34; reducer&#34;。 &#34;减速机的功能&#34;需要&#34;分组键&#34;已在mapper中确定。因此,执行全局累积以获得_id组合是mappers的工作。

更不用说&#34;集合&#34;输出,MongoDB不喜欢&#34;数组&#34; _id值,实际上&#34;错误&#34;如果你试试。

所以这不是&#34;服务器聚合&#34; 的真正工作,而是通过处理&#34;游标&#34;来实现天真的工作。无论如何它都是&#34;所有原始数据&#34; 所以它不像在服务器上运行简化返回的数据输出。处理光标。