Class: Parse::Aggregation
- Inherits:
-
Object
- Object
- Parse::Aggregation
- Defined in:
- lib/parse/query.rb
Overview
Helper class for executing arbitrary MongoDB aggregation pipelines. Provides a consistent interface with results, raw, and result_pointers methods.
Instance Attribute Summary collapse
-
#mongo_direct ⇒ Boolean
readonly
Whether #execute! will route through MongoDB.aggregate instead of Parse Server's REST
/aggregateendpoint. -
#pipeline ⇒ Array<Hash>
readonly
The MongoDB aggregation pipeline stages this Aggregation will execute.
Instance Method Summary collapse
-
#add_stages(*stages) ⇒ Aggregation
Add additional pipeline stages.
-
#any? ⇒ Boolean
Check if there are any results.
-
#count ⇒ Integer
Returns the count of results.
-
#empty? ⇒ Boolean
Check if there are no results.
-
#execute! ⇒ Parse::Response, Array
Execute the aggregation pipeline and cache the response.
-
#execute_direct!(max_time_ms: @max_time_ms) ⇒ Array<Hash>
Execute aggregation directly on MongoDB.
-
#first(limit = 1) ⇒ Parse::Object+
Returns the first result from the aggregation.
-
#initialize(query, pipeline, verbose: nil, mongo_direct: false, max_time_ms: nil, raw_values: false, raw_field_names: false, allow_internal_fields: false) ⇒ Aggregation
constructor
A new instance of Aggregation.
-
#raw { ... } ⇒ Array<Hash>
Returns raw unprocessed results from the aggregation.
-
#result_pointers { ... } ⇒ Array<Parse::Pointer>
(also: #results_pointers)
Returns only pointer objects for all matching results.
-
#results { ... } ⇒ Array<Parse::Object, AggregationResult>
(also: #all)
Returns processed results from the aggregation.
-
#with_stages(*stages) ⇒ Aggregation
Create a new Aggregation with additional stages (non-mutating).
Constructor Details
#initialize(query, pipeline, verbose: nil, mongo_direct: false, max_time_ms: nil, raw_values: false, raw_field_names: false, allow_internal_fields: false) ⇒ Aggregation
Returns a new instance of Aggregation.
6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 |
# File 'lib/parse/query.rb', line 6059 def initialize(query, pipeline, verbose: nil, mongo_direct: false, max_time_ms: nil, raw_values: false, raw_field_names: false, allow_internal_fields: false) @query = query @pipeline = pipeline @cached_response = nil @mongo_direct = mongo_direct @max_time_ms = max_time_ms @raw_values = raw_values @raw_field_names = raw_field_names @allow_internal_fields = allow_internal_fields # Use provided verbose setting, or fall back to query's verbose_aggregate setting @verbose = verbose.nil? ? @query.instance_variable_get(:@verbose_aggregate) : verbose end |
Instance Attribute Details
#mongo_direct ⇒ Boolean (readonly)
Returns whether #execute! will route through
MongoDB.aggregate instead of Parse Server's REST
/aggregate endpoint.
6036 6037 6038 |
# File 'lib/parse/query.rb', line 6036 def mongo_direct @mongo_direct end |
#pipeline ⇒ Array<Hash> (readonly)
Returns the MongoDB aggregation pipeline stages this Aggregation will execute. Useful for previewing the routed pipeline before #execute!, for snapshot-based regression tests, and for debugging the REST-vs-mongo-direct translation.
6031 6032 6033 |
# File 'lib/parse/query.rb', line 6031 def pipeline @pipeline end |
Instance Method Details
#add_stages(*stages) ⇒ Aggregation
Add additional pipeline stages
6287 6288 6289 6290 6291 |
# File 'lib/parse/query.rb', line 6287 def add_stages(*stages) @pipeline.concat(stages.flatten) @cached_response = nil # Clear cache when pipeline changes self end |
#any? ⇒ Boolean
Check if there are any results
6274 6275 6276 |
# File 'lib/parse/query.rb', line 6274 def any? count > 0 end |
#count ⇒ Integer
Returns the count of results
6263 6264 6265 6266 6267 6268 6269 6270 |
# File 'lib/parse/query.rb', line 6263 def count response = execute! if @mongo_direct && defined?(Parse::MongoDB) && Parse::MongoDB.enabled? response.nil? ? 0 : response.count else response.error? ? 0 : response.result.count end end |
#empty? ⇒ Boolean
Check if there are no results
6280 6281 6282 |
# File 'lib/parse/query.rb', line 6280 def empty? count == 0 end |
#execute! ⇒ Parse::Response, Array
Execute the aggregation pipeline and cache the response
6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 |
# File 'lib/parse/query.rb', line 6075 def execute! return @cached_response if @cached_response if @verbose puts "[VERBOSE AGGREGATE] Custom aggregation pipeline:" puts JSON.pretty_generate(@pipeline) puts "[VERBOSE AGGREGATE] Sending to: #{@query.instance_variable_get(:@table)}" puts "[VERBOSE AGGREGATE] Using MongoDB direct: #{@mongo_direct}" end if @mongo_direct && defined?(Parse::MongoDB) && Parse::MongoDB.enabled? @cached_response = execute_direct! else # REST /aggregate is master-key-only. An ambient Parse.with_session # block would suppress the master key via session_token, causing a # 401/403. Force use_master_key unless the caller explicitly disabled # it (use_master_key: false is a deliberate client-mode decision). # `.dup` keeps the master-key flip local to this call even if `_opts` # ever returns a shared/memoized hash. rest_opts = @query.send(:_opts).dup rest_opts[:use_master_key] = true unless rest_opts[:use_master_key] == false @cached_response = @query.client.aggregate_pipeline( @query.instance_variable_get(:@table), @pipeline, headers: {}, raw_values: @raw_values, raw_field_names: @raw_field_names, **rest_opts, ) end if @verbose if @mongo_direct && defined?(Parse::MongoDB) && Parse::MongoDB.enabled? puts "[VERBOSE AGGREGATE] Response result count: #{@cached_response&.count}" else puts "[VERBOSE AGGREGATE] Response success?: #{@cached_response.success?}" puts "[VERBOSE AGGREGATE] Response result count: #{@cached_response.result&.count}" end end @cached_response end |
#execute_direct!(max_time_ms: @max_time_ms) ⇒ Array<Hash>
Execute aggregation directly on MongoDB
6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 |
# File 'lib/parse/query.rb', line 6122 def execute_direct!(max_time_ms: @max_time_ms) table = @query.instance_variable_get(:@table) auth_kwargs = @query.send(:mongo_direct_auth_kwargs) # Forward the parent query's index hint so `query.hint(...).aggregate(...)` # honors it on the mongo-direct path too (parity with results_direct / # count_direct / distinct_direct). hint = @query.instance_variable_get(:@hint) Parse::MongoDB.aggregate(table, @pipeline, max_time_ms: max_time_ms, hint: hint, allow_internal_fields: @allow_internal_fields, **auth_kwargs) end |
#first(limit = 1) ⇒ Parse::Object+
Returns the first result from the aggregation
6256 6257 6258 6259 |
# File 'lib/parse/query.rb', line 6256 def first(limit = 1) items = results.first(limit) limit == 1 ? items.first : items end |
#raw { ... } ⇒ Array<Hash>
Returns raw unprocessed results from the aggregation
6220 6221 6222 6223 6224 6225 6226 6227 6228 |
# File 'lib/parse/query.rb', line 6220 def raw(&block) response = execute! return [] if response.respond_to?(:error?) && response.error? items = response.respond_to?(:result) ? response.result : response items = [] unless items.is_a?(Array) return items.each(&block) if block_given? items end |
#result_pointers { ... } ⇒ Array<Parse::Pointer> Also known as: results_pointers
Returns only pointer objects for all matching results
6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 |
# File 'lib/parse/query.rb', line 6233 def result_pointers(&block) response = execute! if @mongo_direct && defined?(Parse::MongoDB) && Parse::MongoDB.enabled? return [] if response.nil? || response.empty? # Convert MongoDB results to Parse format first converted = Parse::MongoDB.convert_documents_to_parse(response, @query.instance_variable_get(:@table)) items = @query.send(:to_pointers, converted) else return [] if response.error? items = @query.send(:to_pointers, response.result) end return items.each(&block) if block_given? items end |
#results { ... } ⇒ Array<Parse::Object, AggregationResult> Also known as: all
Returns processed results from the aggregation.
- Standard Parse documents (with objectId) are returned as Parse::Object instances
- Custom aggregation results (from $group, $project, etc.) are returned as AggregationResult objects that support both hash access and method access
6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 |
# File 'lib/parse/query.rb', line 6140 def results(&block) response = execute! if @mongo_direct && defined?(Parse::MongoDB) && Parse::MongoDB.enabled? # For MongoDB direct, branch per-row on the *raw* document: real Parse # docs always carry _created_at / _updated_at, while $group rows reuse # _id as the group key. We must not feed group rows through # convert_document_to_parse, which would rename _id → objectId and # fool the Parse-document heuristic. return [] if response.nil? || response.empty? table = @query.instance_variable_get(:@table) items = response.map { |raw| convert_direct_aggregation_item(raw, table) } else return [] if response.error? items = response.result.map { |item| convert_aggregation_item(item) } end return items.each(&block) if block_given? items end |
#with_stages(*stages) ⇒ Aggregation
Create a new Aggregation with additional stages (non-mutating)
6296 6297 6298 |
# File 'lib/parse/query.rb', line 6296 def with_stages(*stages) Aggregation.new(@query, @pipeline + stages.flatten, verbose: @verbose) end |