私はmongodb集計フレームワークを使用しており、以下に示すようにいくつかの計算を行っています
db.RptAgg.aggregate(
{ $group :
{ _id : {Region:"$RegionTxt",Mth:"$Month"},
ActSls:{$sum:"$ActSls"},
PlnSls:{$sum:"$PlnSls"}
}
},
{ $project :
{
ActSls:1,
PlnSls:1,
ActToPln:{$cond:[{ $ne: ["$PlnSls", 0] },{$multiply:[{$divide: ['$ActSls', '$PlnSls']},100]},0]}
}
}
);
結果を小数点第2位で四捨五入するための最良かつ最も簡単な方法を見つけようとしています。以下は私の結果です
{
"result" : [
{
"_id" : {
"Region" : "East",
"Mth" : 201301
},
"ActSls" : 72,
"PlnSls" : 102,
"ActToPln" : 70.58823529411765
}
],
"ok" : 1
}
「ActToPln」に70.59を表示してほしい"ActToPln":70.58823529411765の代わりに、集約フレームワーク自体からの結果。アプリケーションで丸めを行わないようにしたい
同じことを手伝ってくれませんか。
以下は私が使用したデータセットです。
{
"_id" : ObjectId("51d67ef69557c507cb172572"),
"RegionTxt" : "East",
"Month" : 201301,
"Date" : "2013-01-01",
"ActSls" : 31,
"PlnSls" : 51
}
{
"_id" : ObjectId("51d67ef69557c507cb172573"),
"RegionTxt" : "East",
"Month" : 201301,
"Date" : "2013-01-02",
"ActSls" : 41,
"PlnSls" : 51
}
前もって感謝します。南都
$round
演算子はありませんが、これは集計フレームワークで実行できます。特定の順序で実行すると、通常、浮動小数点の精度の問題を回避できます。
> db.a.save({x:1.23456789})
> db.a.save({x:9.87654321})
> db.a.aggregate([{$project:{ _id:0,
y:{$divide:[
{$subtract:[
{$multiply:['$x',100]},
{$mod:[{$multiply:['$x',100]}, 1]}
]},
100]}
}}])
{ "y" : 1.23 }
{ "y" : 9.87 }
問題の既存のパイプラインを考慮して、以下を置き換えます。
{$multiply:[{$divide: ['$ActSls', '$PlnSls']},100]}
と
{$divide:[
{$subtract:[
{$multiply:[
{$divide: ['$ActSls','$PlnSls']},
10000
]},
{$mod:[
{$multiply:[{$divide: ['$ActSls','$PlnSls']}, 10000 ]},
1]}
]},
100
]}
あなたのサンプルデータポイントでこれは結果です:
{ "ActSls" : 31, "PlnSls" : 51, "ActToPln" : 60.78 }
{ "ActSls" : 41, "PlnSls" : 51, "ActToPln" : 80.39 }
{ "ActSls" : 72, "PlnSls" : 102, "ActToPln" : 70.58 }
理由はわかりませんが、(このページの)すべての回答で12.34
ために 12.345
。だから私は自分のプロジェクトステージを書きました:
x = 12.345
{'$project': {
y: {'$divide': [{'$trunc': {'$add': [{'$multiply': ['$x', 100]}, 0.5]}}, 100]},
}},
それは与えます 12.35
。
これは簡単な算術であり、トリックはありません:
round half up
ただし、ネガティブの場合は正しく機能しません(私の集計ではそれで十分でした)。両方の(ポジティブとネガティブ)ケースでは、abs
と一緒に使用する必要があります。
{'$project': {
z: {'$multiply': [
{'$divide': ['$x', {'$abs': '$x'}]},
{'$divide': [{'$trunc': {'$add': [{'$multiply': [{'$abs': '$x'}, 100]}, 0.5]}}, 100]}
]},
}}
ここでは、数値の符号を取得し、元の数値をabsでラップしてから、出力を丸めて符号を乗算しています。
Mongo 4.2
以降、新しい$round
集計演算子が追加されましたを丸めるために使用できますnumber指定された10進数に一定の精度でplace:
{$ round:[<number>、<place>]}
集計パイプライン内でそのまま使用できます(ここでは、x
sを2
の小数点以下の桁数に丸めます)。
// db.collection.insert([{x: 1.23456}, {x: 9.87654}, {x: 0.055543}, {x: 12.345}])
db.collection.aggregate([{ $project: { "rounded_x": { $round: ["$x", 2] }}}])
// [{"rounded_x": 1.23}, {"rounded_x": 9.88}, {"rounded_x": 0.06}, {"rounded_x": 12.35}]
place
パラメーターはオプションであり、省略した場合は整数全体に丸められます(つまり、小数点以下0桁で丸められます)。
mongo-round はうまく機能します。私が見つけた最もクリーンな方法。
数が3.3333333
var round = require('mongo-round');
db.myCollection.aggregate([
{ $project: {
roundAmount: round('$amount', 2) // it will become 3.33
} }
]);
このソリューションでは、2 dpに正しく切り上げまたは切り下げます。
"rounded" : {
$subtract:[
{$add:['$absolute',0.0049999999999999999]},
{$mod:[{$add:['$absolute',0.0049999999999999999]}, 0.01]}
]
}
たとえば、1.2499は1.25に切り上げられますが、1.2501は1.25に切り下げられます。
ノート:
現在のバージョンのAggregation Frameworkには、ラウンド演算子はありません。あなたはこのスニペットを試すことができます:
> db.a.save({x:1.23456789})
> db.a.save({x:9.87654321})
> db.a.aggregate([{$project:{y:{$subtract:['$x',{$mod:['$x', 0.01]}]}}}])
{
"result" : [
{
"_id" : ObjectId("51d72eab32549f94da161448"),
"y" : 1.23
},
{
"_id" : ObjectId("51d72ebe32549f94da161449"),
"y" : 9.870000000000001
}
],
"ok" : 1
}
しかし、ご覧のとおり、精度の問題のため、このソリューションはうまく機能しません。この場合の最も簡単な方法は、@wiredprairie
のアドバイスに従い、アプリケーションでround
sを作成することです。
MongoDBにこの関数が欠けているのは残念です。私は彼らがすぐにそれを追加することを望んでいます。
しかし、長い集計パイプラインを思いつきました。認めると、それは効率的ではないかもしれませんが、丸めのルールを尊重します。
db.t.aggregate([{
$project: {
_id: 0,
number: {
$let: {
vars: {
factor: {
$pow: [10, 3]
},
},
in: {
$let: {
vars: {
num: {$multiply: ["$$factor", "$number"]},
},
in: {
$switch: {
branches: [
{case: {$gte: ["$$num", {$add: [{$floor: "$$num"}, 0.5]}]}, then: {$divide:[ {$add: [{$floor: "$$num"}, 1.0]},"$$factor"]}},
{case: {$lt: ["$$num", {$add: [{$floor: "$$num"}, 0.5]}]}, then: {$divide:[{$floor: "$$num"}, "$$factor"]}}
]
}
}
}
}
}
}
}
}])
t
という名前のコレクションに次のドキュメントがあるとします。
{ number" : 2.341567 }
{ number" : 2.0012 }
{ number" : 2.0012223 }
上記のクエリを実行した後、私は得ました:
{ "number" : 2.342 }
{ "number" : 2.001 }
{ "number" : 2.001 }
rounded:{'$multiply': [{ "$cond": [{ "$gte": [ "$x", 0 ] }, 1,-1 ]},{'$divide': [{'$trunc': {'$add': [{'$multiply': [{'$abs': '$x'}, {$pow:[10,2]}]}, 0.5]}}, {$pow:[10,2]}]}]}
egvoの解はクールですが、ゼロの場合はゼロによる除算を提供します。 $ condを回避するために、サインを検出するために使用できます
(xをfield_nameで置き換え、数値2を目的の10進数で置き換えます)
{$divide:[
{$cond: { if: { $gte: [ {$mod:[{$multiply:['$dollarAmount',100]}, 1]}, 0.5 ] }, then: {$add: [{$subtract:[
{$multiply:['$dollarAmount',100]},
{$mod:[{$multiply:['$dollarAmount',100]}, 1]}
]}
,1]}, else: {$subtract:[
{$multiply:['$dollarAmount',100]},
{$mod:[{$multiply:['$dollarAmount',100]}, 1]}
]} }}
,
100]}
うまくいけば、これらは四捨五入に役立ちます。