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.
6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 |
# File 'lib/parse/query.rb', line 6150 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.
6127 6128 6129 |
# File 'lib/parse/query.rb', line 6127 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.
6122 6123 6124 |
# File 'lib/parse/query.rb', line 6122 def pipeline @pipeline end |
Instance Method Details
#add_stages(*stages) ⇒ Aggregation
Add additional pipeline stages
6378 6379 6380 6381 6382 |
# File 'lib/parse/query.rb', line 6378 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
6365 6366 6367 |
# File 'lib/parse/query.rb', line 6365 def any? count > 0 end |
#count ⇒ Integer
Returns the count of results
6354 6355 6356 6357 6358 6359 6360 6361 |
# File 'lib/parse/query.rb', line 6354 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
6371 6372 6373 |
# File 'lib/parse/query.rb', line 6371 def empty? count == 0 end |
#execute! ⇒ Parse::Response, Array
Execute the aggregation pipeline and cache the response
6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 |
# File 'lib/parse/query.rb', line 6166 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
6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 |
# File 'lib/parse/query.rb', line 6213 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
6347 6348 6349 6350 |
# File 'lib/parse/query.rb', line 6347 def first(limit = 1) items = results.first(limit) limit == 1 ? items.first : items end |
#raw { ... } ⇒ Array<Hash>
Returns raw unprocessed results from the aggregation
6311 6312 6313 6314 6315 6316 6317 6318 6319 |
# File 'lib/parse/query.rb', line 6311 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
6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 |
# File 'lib/parse/query.rb', line 6324 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
6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 |
# File 'lib/parse/query.rb', line 6231 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)
6387 6388 6389 |
# File 'lib/parse/query.rb', line 6387 def with_stages(*stages) Aggregation.new(@query, @pipeline + stages.flatten, verbose: @verbose) end |