Module: ActiveMedian::Mongoid

Defined in:
lib/active_median/mongoid.rb

Instance Method Summary collapse

Instance Method Details

#median(column) ⇒ Object



3
4
5
# File 'lib/active_median/mongoid.rb', line 3

def median(column)
  percentile(column, 0.5)
end

#percentile(column, percentile) ⇒ Object

Raises:

  • (ArgumentError)


8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 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