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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OTE1ODI0NTJiYWU0MzExYjg0MWFmNDBjM2EzOTg5YzRjYjVkYzYyZQ==
4
+ MmQzMDM0OWZiOTYzNzQzNzM2YTg4MjEyOGI0NWIyOWQ4MTI3ZDk3Mg==
5
5
  data.tar.gz: !binary |-
6
- ZWI2ODM4NWRlNjNiNTY5NGJkN2M2MDdjM2FlODIwNGJiMzFhMGJlNw==
6
+ OGRkNmVlYzhkNTQzY2Q3ZGUzYjYyMWQ1NjYzM2E4YmNjNGM4NDUzNQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- OTJiNTEyNzE2MTk0ZjMzNDQ2ZDgyNDU4MjBkNzk3YjVjZDgwYmFiOWE1Mzg2
10
- YmNiNzU3MjJkYjg1NTZkYWY0NTU1MzE2YjVkMzBjNzg0MWQ4M2ViMmM4OTA2
11
- NWVjMzA5YTlmNzdhMTdmOGEzMGNiZjY0MjMxZmIxZGFkOTE2ZTE=
9
+ MDdmZmE0ODA4MjUyM2U4ZTcyYTk0ODlkMzkxYTFkY2U2ZjM2NzM4NjNmMGVi
10
+ YTc4NWZmMzM0YTk1M2RlMjE1NDMxNDIwYTUzYzllODg3ZTc1ZTEwZTVlNWUx
11
+ MDM0MTAwMjhjYzY0YjlhOGQ5NTMyYjcyOGEzODU0N2E3NTVmNDU=
12
12
  data.tar.gz: !binary |-
13
- MTM5MmIzOGE3NTFlNTBjMTU4NjBkOWE5ZDVlYjU4MjBjNTQyMjA4Nzk1MWJh
14
- MDdjYTg0NWM0MmRkNjgyZGUwMTc0NjQyMDFmZjNhZjJjMGRkZDJhMTZiZmYx
15
- ZWMyMzM0ODlhYTI5MzcxZmViMmNmMmM4MTVhYzg4NmQ2MWMxZmI=
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,14 @@
1
+ module Mongoid
2
+ module Contextual
3
+ module Aggregable
4
+ module Commands
5
+ class Group < Base
6
+ def initialize(key, *args)
7
+ super('$group', *args.unshift({'_id' => normalize_id(key)}))
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,15 @@
1
+ module Mongoid
2
+ module Contextual
3
+ module Aggregable
4
+ module Commands
5
+ class Match < Base
6
+ def initialize(*args)
7
+ super('$match', *args)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+
@@ -0,0 +1,14 @@
1
+ module Mongoid
2
+ module Contextual
3
+ module Aggregable
4
+ module Commands
5
+ class Sort < Base
6
+ def initialize(args)
7
+ super('$sort', args)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -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
@@ -1 +1 @@
1
- require 'mongoid/contextual/aggregable/mongo'
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.0
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: Aggregation extender for mongoid
48
+ summary: mongoid aggregation extender.
43
49
  test_files: []
44
50
  has_rdoc: