Reputation: 174
I have this query in mongoDB and that produces the result that I want. But now I'm trying to use that in java.
This is the query in MongoDB:
var red = function(doc, out) {
out.count_order++;
out.sum_qty += doc.quantity;
out.sum_base_price += doc.extendedprice;
out.sum_disc_price += doc.extendedprice * (1 - doc.discount);
out.sum_charge += doc.extendedprice * (1 - doc.discount) * (1 + doc.tax);
out.avg_disc += doc.discount;
};
var avg = function(out) {
out.avg_qty = out.sum_qty / out.count_order;
out.avg_price = out.sum_base_price / out.count_order;
out.avg_disc = out.avg_disc / out.count_order;
};
db.lineitems.group( {
key : { returnflag : true, linestatus : true},
cond : { "shipdate" : {$lte: 19980801}},
initial: { count_order : 0, sum_qty : 0, sum_base_price : 0, sum_disc_price : 0,
sum_charge : 0, avg_disc : 0},
reduce : red,
finalize : avg
});
And now the way I'm using it in Java but I don't know how to use the avg function.
String avg = "var avg = function(out) {"
+ "out.avg_qty = out.sum_qty / out.count_order;"
+ "out.avg_price = out.sum_base_price / out.count_order;"
+ "out.avg_disc = out.avg_disc / out.count_order;};";
String reduce = "function(doc, out) {"
+ "out.count_order++;"
+ "out.sum_qty += doc.quantity;"
+ "out.sum_base_price += doc.extendedprice;"
+ "out.sum_disc_price += doc.extendedprice * (1 - doc.discount);"
+ "out.sum_charge += doc.extendedprice * (1 - doc.discount) * (1 + doc.tax);"
+ "out.avg_disc += doc.discount;};";
String finalize = "function(out) {"
+ "out.avg_qty = out.sum_qty / out.count_order;"
+ "out.avg_price = out.sum_base_price / out.count_order;"
+ "out.avg_disc = out.avg_disc / out.count_order;};";
MapReduceIterable<Document> iterable = collection.mapReduce(**????**, reduce).finalizeFunction(finalize);
How can I use that function?
Upvotes: 3
Views: 101
Reputation: 50436
You would be better off using the aggreation framework for this than calling the .group()
method, which is of course an older implementation before the aggregation framework actually existed.
The logic as applied in the shell would be:
db.lineitems.aggregate([
{ "$match": { "shipdate": { "$lte": 19980801 } },
{ "$group": {
"_id": {
"returnflag": "$returnflag",
"linestatus": "$linestatus"
},
"count": { "$sum": 1 },
"sum_qty": { "$sum": "$quantity" },
"avg_qty": { "$avg": "$quantity" },
"sum_base_price": { "$sum": "$extendedprice" },
"avg_base_price": { "$avg": "$extendedprice" },
"sum_disc_price": {
"$sum": {
"$multiply": [
"$extendedprice",
{ "$subtract": [ 1, "$discount" ] }
]
}
},
"avg_disc_price": {
"$avg": {
"$multiply": [
"$extendedprice",
{ "$subtract": [ 1, "$discount" ] }
]
}
},
"sum_charge": {
"$sum": {
"$multiply": [
"$extendedprice",
{ "$subtract": [ 1, "$discount" ] },
{ "$add": [ 1, "$tax" ] }
]
}
},
"avg_disc": { "$avg": "$discount" }
}}
])
The aggregation framework as a very efficient $group
pipeline stage operator which does all the same things in native coded operations. There is $sum
and $avg
accumulators built in as well as the other math operations.
In short, as "natively coded" and not relying on "JavaScript interpretation", the execution is much faster than what .group()
can provide. Plus it really should be fairly straightforward to understand.
Translating that to Java would be something like
List<Document> pipeline = Arrays.<Document>asList(
new Document(
"$match", new Document(
"shipdate", new Document(
"$lte", 19980801
)
)
),
new Document(
"$group", new Document(
"_id", new Document(
"returnflag", "$returnflag"
).append( "linestatus", "$linestatus" )
).append(
"count", new Document( "$sum", 1 )
).append(
"sum_qty", new Document( "$sum", "$quantity" )
).append(
"avg_qty", new Document( "$avg", "$quantity" )
).append(
"sum_base_price", new Document( "$sum", "$extendedprice" )
).append(
"avg_base_price", new Document( "$avg", "$extendedprice" )
).append(
"sum_disc_price", new Document(
"$sum", new Document(
"$multiply", Arrays.asList(
"$extendedprice",
new Document(
"$subtract", Arrays.asList(1, "$discount")
)
)
)
)
).append(
"avg_disc_price", new Document(
"$avg", new Document(
"$multiply", Arrays.asList(
"$extendedprice",
new Document(
"$subtract", Arrays.asList(1, "$discount")
)
)
)
)
).append(
"sum_charge", new Document(
"$sum", new Document(
"$multiply", Arrays.asList(
"$extendedprice",
new Document(
"$subtract", Arrays.asList(1, "$discount")
),
new Document(
"$add", Arrays.asList(1, "$tax")
)
)
)
)
).append(
"avg_disc", new Document( "$avg", "$discount" )
)
)
);
AggregateIterable<Document> result = collection.aggregate(pipeline);
Upvotes: 1