聚合以按大小创建文档组

Aggregate to Create Groups of Documents by Size

本文关键字:创建 文档      更新时间:2024-06-06

我有一个名为"订单"的集合。此集合中的每个订单都有一个产品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聚合中可能吗?

这实际上不是您在数组聚合过程中会做的事情。这在聚合框架中是不可能的,因为您需要跨文档维护值。除了"临界点"之外,没有其他自然的分组边界,"products"的总收集元素变成三个或更多值,而这种累积需要"全局",这是聚合框架不可用的。

MapReduce有"全局",但当您考虑到所涉及的操作时,这不会"减少"任何内容。当然存在"积累",但这只是处理到上述"临界点"的总数据的一个因素。返回的实际数据与存储在集合中的数据"完全相同",只是以输出格式重新组织

因此,跨文档的积累最好在处理"游标"时处理。因此,用更多的项目来扩展您的样本数据,以说明另一点:

{ "_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 ] }

然后,您基本上是在用逻辑处理"光标"结果来进行累积:

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 ] }

因此,输出采用不同的"格式"answers"累积",因此所有"products"数据最多存在三个项,但实际上集合中的数据非常相同,没有减少。这是重要的一点。

因此,累积过程需要"global",在这里您可以建立累积_id值的列表以及总products。还要注意的是,由于[4,5]累积的数据实际上会超过三个项目,因此剩余项目将转入下一个"分组"。

如前所述,现在mapReduce确实有"globals",但这种跨文档的积累意味着通常会有一些剩余的东西没有"发射",因为总"products"还没有达到三个的计数。

mapReduce的情况实际上只是作为服务器上的JavaScript运行程序,因为这种累积实际上是在"mapper"函数而不是"reducer"中完成的。"reducer"的功能要求在映射器中已经确定"grouping key"。因此,映射器的工作是进行全局累积以获得_id组合。

更不用说在"collection"输出中,MongoDB不喜欢_id值的"arrays",如果您尝试,它实际上会"出错"。

因此,这并不是"服务器聚合"的真正工作,而是通过处理"游标"来完成的。这是"所有原始数据",所以它不像在服务器上运行减少了返回的数据输出。处理光标。