我有一个名为inbound_pos
的集合,其文档中有一个名为lines
的密钥。一个例子如下:
{
"_id": ObjectId("537e16cf8be10a5e7e000008"),
"cdt": ISODate("2014-05-22T15:25:03.379Z"),
"comments": [
[
]
],
"cust_shipto_id": "103",
"doc_dt": "20140522",
"isa_control_id": "000030456",
"kind": "edi",
"lines": [
{
"linenumber": "1",
"net_qty": NumberInt(10),
"uom": "EA",
"unitcost": 10.04,
"v_nmbr": "005-2964",
"tm_desc": "NA"
},
{
"linenumber": "2",
"net_qty": NumberInt(10),
"uom": "EA",
"unitcost": 13.59,
"v_nmbr": "005-2966",
"tm_desc": "NA"
},
{
"linenumber": "3",
"net_qty": NumberInt(6),
"uom": "BX",
"unitcost": 18.36,
"v_nmbr": "2201254",
"tm_desc": "LANTISEPTIC"
}
]
}
在构成lines
数组的每个对象中,v_nmbr
,net_qty
和unitcost
键表示正在购买的特定商品,购买的数量为该项目,以及该项目的单价。
我要做的是获取集合中所有文档的每v_nmbr
个花费的总金额。 map-reduce查询如下:
db.inbound_pos.mapReduce(function() {
for (var i=0; i<this.lines.length; i++) {
emit(this.lines[i].v_nmbr, this.lines[i])
}
}, function(key, values) {
var totalExpenses = 0;
for (var i=0; i<values.length; i++) {
totalExpenses += values[i].unitcost * values[i].net_qty
}
return totalExpenses
}, {
out: "total_expenses_per_item"
})
此查询会为已购买多次的所有商品正确生成总金额,但对于仅购买过一次的商品则无效。
以下是一些示例输出:
成功 (项目购买了20次)
{
"_id": "005-BUHW2076HRF",
"value": 2366.4
}
(项目被购买2次):
{
"_id": "P54072",
"value": 29.13
}
失败(商品只购买一次):
{
"_id": "OTC11780",
"value": {
"linenumber": "1",
"v_nmbr": "OTC11780",
"net_qty": NumberInt(5),
"unitcost": 13.68,
"uom": "BT",
"tm_desc": "VITAMIN E 1000 IU SOFTGEL 100/BTL"
}
}
如果您有时间,我们将非常感谢您的帮助。
答案 0 :(得分:1)
From the documentation:MongoDB不会为只有一个值的键调用reduce函数。它只返回映射值作为结果。
但是MongoDB无论如何都会调用单个映射值的finalize函数,所以你可以在那里修改结果。
最佳解决方案是遵循以下规则:reduce函数的返回对象的类型必须与map函数发出的值的类型相同。
在你的情况下,我会以这种方式做map-reduce:
db.inbound_pos.mapReduce(function() {
for (var i=0; i<this.lines.length; i++) {
emit(this.lines[i].v_nmbr, this.lines[i].unitcost * this.lines[i].net_qty)
}
}, function(key, values) {
var totalExpenses = 0;
for (var i=0; i<values.length; i++) {
totalExpenses += values[i]
}
return totalExpenses
}, {
out: "total_expenses_per_item"
})
答案 1 :(得分:1)
试试这个:
db.inbound_pos.mapReduce(function() {
for (var i=0; i<this.lines.length; i++) {
emit(this.lines[i].v_nmbr, this.lines[i])
}
}, function(key, values) {
var totalExpenses = 0;
for (var i=0; i<values.length; i++) {
totalExpenses += values[i].unitcost * values[i].net_qty
}
return totalExpenses
}, {
finalize: function(key,reducedValue) {
if (typeof reducedValue.linenumber != 'undefined') {
return reducedValue.unitcost;
} else {
return reducedValue;
}
},
out: "total_expenses_per_item"
});
如果只有一个值,则map reduce不会进入reduce阶段,在这种情况下,你可以使用finalize函数只返回你想要的值。