mongoid_aggregates 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/lib/mongoid/contextual/aggregable/aggregates.rb +76 -0
- data/lib/mongoid/contextual/aggregable/commands/base.rb +27 -0
- data/lib/mongoid/contextual/aggregable/commands/group.rb +14 -0
- data/lib/mongoid/contextual/aggregable/commands/match.rb +15 -0
- data/lib/mongoid/contextual/aggregable/commands/sort.rb +14 -0
- data/lib/mongoid/contextual/aggregable/mongo_ex.rb +157 -0
- data/lib/mongoid_aggregates.rb +1 -1
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MmQzMDM0OWZiOTYzNzQzNzM2YTg4MjEyOGI0NWIyOWQ4MTI3ZDk3Mg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
OGRkNmVlYzhkNTQzY2Q3ZGUzYjYyMWQ1NjYzM2E4YmNjNGM4NDUzNQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MDdmZmE0ODA4MjUyM2U4ZTcyYTk0ODlkMzkxYTFkY2U2ZjM2NzM4NjNmMGVi
|
10
|
+
YTc4NWZmMzM0YTk1M2RlMjE1NDMxNDIwYTUzYzllODg3ZTc1ZTEwZTVlNWUx
|
11
|
+
MDM0MTAwMjhjYzY0YjlhOGQ5NTMyYjcyOGEzODU0N2E3NTVmNDU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YjU4NzU5N2U1ZTNlNzQ2OTZiNmFlMmViNDU4MjI2NDQwMTZjNzk3NTE1YmRm
|
14
|
+
ZTU0YzM3NDZmOWE5MWM2ODZmMmU4NjMxZjExMTFiMjYyYjliYWY3YTEzZWZl
|
15
|
+
MmJjZmYyOTE1NGIxOTdkMjYyNDJjNzM5ODVjNWM0YjQ0YmE2MDk=
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require_relative "commands/base"
|
2
|
+
require_relative "commands/match"
|
3
|
+
require_relative "commands/group"
|
4
|
+
require_relative "commands/sort"
|
5
|
+
|
6
|
+
module Mongoid
|
7
|
+
module Contextual
|
8
|
+
module Aggregable
|
9
|
+
# Contains behaviour for aggregating values in Mongo.
|
10
|
+
class Aggregates
|
11
|
+
def initialize(context)
|
12
|
+
@context = context
|
13
|
+
@commands = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def all
|
17
|
+
@context.collection.aggregate(@commands)
|
18
|
+
end
|
19
|
+
|
20
|
+
def group(key, *args)
|
21
|
+
@commands.push(Commands::Group.new(key, *args))
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def sort(*args)
|
26
|
+
@commands.push(Commands::Sort.new(*args))
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def explain
|
31
|
+
@commands.to_json
|
32
|
+
end
|
33
|
+
|
34
|
+
def sum(field)
|
35
|
+
all.inject(0) {
|
36
|
+
|sum, item| sum + (item[field.to_s] || 0)
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def compute(field)
|
41
|
+
res = all.inject(Hash.new 0) {
|
42
|
+
|compute, item| compute[:count] += 1; compute[:sum] += item["#{field}"] unless item["#{field}"].nil?; compute
|
43
|
+
}
|
44
|
+
res[:avg] = res[:sum] / (res[:count] != 0 ? res[:count] : 1 )
|
45
|
+
res
|
46
|
+
end
|
47
|
+
|
48
|
+
def count
|
49
|
+
all.count
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
def method_missing(name, *args, &block)
|
55
|
+
if @context.scopes.has_key?(name)
|
56
|
+
criteria = @context.scopes[name][:scope].call(*args)
|
57
|
+
@commands.push(to_match(criteria))
|
58
|
+
elsif @context.respond_to?(name)
|
59
|
+
criteria = @context.send(name, *args)
|
60
|
+
@commands.push(to_match(criteria))
|
61
|
+
else
|
62
|
+
raise Errors::UnknownAttribute.new(@context, name)
|
63
|
+
end
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_match(criteria)
|
68
|
+
hash = criteria.selector.inject({}) {|hash, (key, val)| hash[key] = val.is_a?(Array) ? val[0] : val; hash}
|
69
|
+
Commands::Match.new(hash)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Contextual
|
3
|
+
module Aggregable
|
4
|
+
# Contains behaviour for aggregating values in Mongo.
|
5
|
+
module Commands
|
6
|
+
class Base < Hash
|
7
|
+
def initialize(name, *args)
|
8
|
+
values = args.inject({}) { |res, hash| res.merge(hash) }
|
9
|
+
self[name] = values
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
def normalize_id(key)
|
14
|
+
if (key.present? && (key.is_a?(String) || key.is_a?(Symbol)))
|
15
|
+
key.to_s =~ /^\$.+/ ? key : "$#{key}"
|
16
|
+
elsif key.is_a?(Hash)
|
17
|
+
key
|
18
|
+
else
|
19
|
+
'null'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "mongoid/contextual/aggregable/aggregates"
|
3
|
+
|
4
|
+
module Mongoid
|
5
|
+
module Contextual
|
6
|
+
module Aggregable
|
7
|
+
# Contains behaviour for aggregating values in Mongo.
|
8
|
+
module MongoEx
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
# Get all the aggregate values for the provided field.
|
14
|
+
#
|
15
|
+
# @example Get all the aggregate values.
|
16
|
+
# aggregable.aggregates(:likes)
|
17
|
+
#
|
18
|
+
# @param [ String, Symbol ] field The field name.
|
19
|
+
#
|
20
|
+
# @return [ Hash ] The aggregate values in the form:
|
21
|
+
# {
|
22
|
+
# "count" => 2.0,
|
23
|
+
# "max" => 1000.0,
|
24
|
+
# "min" => 500.0,
|
25
|
+
# "sum" => 1500.0,
|
26
|
+
# "avg" => 750.0
|
27
|
+
# }
|
28
|
+
#
|
29
|
+
# @since 3.0.0
|
30
|
+
def aggregates(field = nil)
|
31
|
+
if (field.present?)
|
32
|
+
if query.count > 0
|
33
|
+
result = collection.aggregate(pipeline(field)).to_a
|
34
|
+
if result.empty?
|
35
|
+
{"count" => query.count, "avg" => 0, "sum" => 0}
|
36
|
+
else
|
37
|
+
result.first
|
38
|
+
end
|
39
|
+
else
|
40
|
+
{"count" => 0}
|
41
|
+
end
|
42
|
+
else
|
43
|
+
Aggregates.new(self)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Get the average value of the provided field.
|
48
|
+
#
|
49
|
+
# @example Get the average of a single field.
|
50
|
+
# aggregable.avg(:likes)
|
51
|
+
#
|
52
|
+
# @param [ Symbol ] field The field to average.
|
53
|
+
#
|
54
|
+
# @return [ Float ] The average.
|
55
|
+
#
|
56
|
+
# @since 3.0.0
|
57
|
+
def avg(field)
|
58
|
+
aggregates(field)["avg"]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Get the max value of the provided field. If provided a block, will
|
62
|
+
# return the Document with the greatest value for the field, in
|
63
|
+
# accordance with Ruby's enumerable API.
|
64
|
+
#
|
65
|
+
# @example Get the max of a single field.
|
66
|
+
# aggregable.max(:likes)
|
67
|
+
#
|
68
|
+
# @example Get the document with the max value.
|
69
|
+
# aggregable.max do |a, b|
|
70
|
+
# a.likes <=> b.likes
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# @param [ Symbol ] field The field to max.
|
74
|
+
#
|
75
|
+
# @return [ Float, Document ] The max value or document with the max
|
76
|
+
# value.
|
77
|
+
#
|
78
|
+
# @since 3.0.0
|
79
|
+
def max(field = nil)
|
80
|
+
block_given? ? super() : aggregates(field)["max"]
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get the min value of the provided field. If provided a block, will
|
84
|
+
# return the Document with the smallest value for the field, in
|
85
|
+
# accordance with Ruby's enumerable API.
|
86
|
+
#
|
87
|
+
# @example Get the min of a single field.
|
88
|
+
# aggregable.min(:likes)
|
89
|
+
#
|
90
|
+
# @example Get the document with the min value.
|
91
|
+
# aggregable.min do |a, b|
|
92
|
+
# a.likes <=> b.likes
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# @param [ Symbol ] field The field to min.
|
96
|
+
#
|
97
|
+
# @return [ Float, Document ] The min value or document with the min
|
98
|
+
# value.
|
99
|
+
#
|
100
|
+
# @since 3.0.0
|
101
|
+
def min(field = nil)
|
102
|
+
block_given? ? super() : aggregates(field)["min"]
|
103
|
+
end
|
104
|
+
|
105
|
+
# Get the sum value of the provided field. If provided a block, will
|
106
|
+
# return the sum in accordance with Ruby's enumerable API.
|
107
|
+
#
|
108
|
+
# @example Get the sum of a single field.
|
109
|
+
# aggregable.sum(:likes)
|
110
|
+
#
|
111
|
+
# @example Get the sum for the provided block.
|
112
|
+
# aggregable.sum(&:likes)
|
113
|
+
#
|
114
|
+
# @param [ Symbol ] field The field to sum.
|
115
|
+
#
|
116
|
+
# @return [ Float ] The sum value.
|
117
|
+
#
|
118
|
+
# @since 3.0.0
|
119
|
+
def sum(field = nil)
|
120
|
+
block_given? ? super() : aggregates(field)["sum"] || 0
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# Get the aggregation pipeline for provided field.
|
126
|
+
#
|
127
|
+
# @api private
|
128
|
+
#
|
129
|
+
# @example Get the pipeline.
|
130
|
+
# aggregable.pipeline(:likes)
|
131
|
+
#
|
132
|
+
# @param [ String, Symbol ] field The name of the field.
|
133
|
+
#
|
134
|
+
# @return [ Array ] The array of pipeline operators.
|
135
|
+
#
|
136
|
+
# @since 3.1.0
|
137
|
+
def pipeline(field)
|
138
|
+
db_field = "$#{database_field_name(field)}"
|
139
|
+
pipeline = []
|
140
|
+
pipeline << {"$match" => criteria.nin(field => nil).selector}
|
141
|
+
pipeline << {"$limit" => criteria.options[:limit]} if criteria.options[:limit]
|
142
|
+
pipeline << {
|
143
|
+
"$group" => {
|
144
|
+
"_id" => field.to_s,
|
145
|
+
"count" => {"$sum" => 1},
|
146
|
+
"max" => {"$max" => db_field},
|
147
|
+
"min" => {"$min" => db_field},
|
148
|
+
"sum" => {"$sum" => db_field},
|
149
|
+
"avg" => {"$avg" => db_field}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
data/lib/mongoid_aggregates.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require 'mongoid/contextual/aggregable/
|
1
|
+
require 'mongoid/contextual/aggregable/mongo_ex'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid_aggregates
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yair Levinson
|
@@ -10,12 +10,18 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2013-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: Aggregation extender for mongoid
|
13
|
+
description: Aggregation extender for mongoid.
|
14
14
|
email: yair@locbox.com
|
15
15
|
executables: []
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
18
18
|
files:
|
19
|
+
- lib/mongoid/contextual/aggregable/aggregates.rb
|
20
|
+
- lib/mongoid/contextual/aggregable/commands/base.rb
|
21
|
+
- lib/mongoid/contextual/aggregable/commands/group.rb
|
22
|
+
- lib/mongoid/contextual/aggregable/commands/match.rb
|
23
|
+
- lib/mongoid/contextual/aggregable/commands/sort.rb
|
24
|
+
- lib/mongoid/contextual/aggregable/mongo_ex.rb
|
19
25
|
- lib/mongoid_aggregates.rb
|
20
26
|
homepage: http://rubygems.org/gems/mongoid_aggregates
|
21
27
|
licenses: []
|
@@ -39,6 +45,6 @@ rubyforge_project:
|
|
39
45
|
rubygems_version: 2.0.3
|
40
46
|
signing_key:
|
41
47
|
specification_version: 4
|
42
|
-
summary:
|
48
|
+
summary: mongoid aggregation extender.
|
43
49
|
test_files: []
|
44
50
|
has_rdoc:
|