module ActiveMedian::Mongoid
Public Instance Methods
median(column)
click to toggle source
# File lib/active_median/mongoid.rb, line 3 def median(column) percentile(column, 0.5) end
percentile(column, percentile)
click to toggle source
www.compose.com/articles/mongo-metrics-finding-a-happy-median/
# File lib/active_median/mongoid.rb, line 8 def percentile(column, percentile) percentile = Float(percentile, exception: false) raise ArgumentError, "invalid percentile" if percentile.nil? raise ArgumentError, "percentile is not between 0 and 1" if percentile < 0 || percentile > 1 relation = all .where(column => {"$ne" => nil}) .asc(column) .group(_id: nil, values: {"$push" => "$#{column}"}, count: {"$sum" => 1}) .project(values: 1, count: {"$subtract" => ["$count", 1]}) .project(values: 1, count: 1, x: {"$multiply" => ["$count", percentile]}) .project(values: 1, count: 1, r: {"$mod" => ["$x", 1]}, i: {"$floor" => "$x"}) .project(values: 1, count: 1, r: 1, i: 1, i2: {"$add" => ["$i", 1]}) .project(values: 1, count: 1, r: 1, i: 1, i2: {"$min" => ["$i2", "$count"]}) .project(r: 1, beginValue: {"$arrayElemAt" => ["$values", "$i"]}, endValue: {"$arrayElemAt" => ["$values", "$i2"]}) .project(r: 1, beginValue: 1, result: {"$subtract" => ["$endValue", "$beginValue"]}) .project(beginValue: 1, result: {"$multiply" => ["$result", "$r"]}) .project(result: {"$add" => ["$beginValue", "$result"]}) res = collection.aggregate(relation.pipeline).first res ? res["result"] : nil end