我有一个名为"订单"的集合。此集合中的每个订单都有一个产品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 ] }
因此,输出采用不同的"格式"one_answers"累积",因此所有"products"
数据最多存在三个项,但实际上集合中的数据非常相同,没有减少。这是重要的一点。
因此,累积过程需要"global",在这里您可以建立累积_id
值的列表以及总products
。还要注意的是,由于[4,5]
累积的数据实际上会超过三个项目,因此剩余项目将转入下一个"分组"。
如前所述,现在mapReduce确实有"globals",但这种跨文档的积累意味着通常会有一些剩余的东西没有"发射",因为总"products"
还没有达到三个的计数。
mapReduce的情况实际上只是作为服务器上的JavaScript运行程序,因为这种累积实际上是在"mapper"函数而不是"reducer"中完成的。"reducer"的功能要求在映射器中已经确定"grouping key"。因此,映射器的工作是进行全局累积以获得_id
组合。
更不用说在"collection"输出中,MongoDB不喜欢_id
值的"arrays",如果您尝试,它实际上会"出错"。
因此,这并不是"服务器聚合"的真正工作,而是通过处理"游标"来完成的。这是"所有原始数据",所以它不像在服务器上运行减少了返回的数据输出。处理光标。