Module: ElasticsearchRecord::Relation::CoreMethods

Defined in:
lib/elasticsearch_record/relation/core_methods.rb

Instance Method Summary collapse

Instance Method Details

#instantiate_records(rows, &block) ⇒ Object



4
5
6
7
8
# File 'lib/elasticsearch_record/relation/core_methods.rb', line 4

def instantiate_records(rows, &block)
  # slurp the total value from the rows (rows = ElasticsearchRecord::Result)
  @total = rows.is_a?(::ElasticsearchRecord::Result) ? rows.total : rows.length
  super
end

#msearch(items = nil, opts = {}) ⇒ Array, ...

Allows to execute several search operations in one request. executes the elasticsearch +msearch+ on the related class-index.

A optionally array of items will be each yielded with a spawn(of the current relation) and item. Each yield-return will resolve its +arel+ which will then transform to multiple queries and send in a single request.

Responses can be refined by providing a +resolve+ option, to resolve specific results from each +ElasticsearchRecord::Result+ (e.g. used to resolve 'aggregations, buckets, ...')

As a default the method returns an array of (resolved) responses in the order of the provided +values+-array. This can be transformed into a hash of keys (provided items) and values (responses) by providing the +transpose+ flag.

WARNING: if the current relation is a +NullRelation+ (#none was assigned), the method directly returns nil!

Examples:

# msearch on the current relation
msearch
# > [ElasticsearchRecord::Result]
# msearch with provided items
msearch([2020, 2019, 2018]).each{ |query, year| query.where!(year: year) }
# > [ElasticsearchRecord::Result, ElasticsearchRecord::Result, ElasticsearchRecord::Result]
# msearch with refining options
msearch([2020, 2019, 2018], resolve: :aggregations, transpose: true).each{ |query, year| query.where!(year: year).aggregate!(:total, { sum: { field: :count }}) }
# > {2020 => {...aggs...}, 2019 => {...aggs...}, 2018 => {...aggs...}}
# msearch with none (NullRelation)
scope = spawn.none
scope.msearch([2020, 2019, 2018]).each{ |query, year| ... }
# > nil

Parameters:

  • items (nil, Array) (defaults to: nil)
    • items to be yielded and used to provide individual queries (yields: |spawn, value| )
  • opts (Hash) (defaults to: {})
    • additional options to refine the results
  • opts[Symbol] (Hash)

    a customizable set of options

  • opts[Boolean] (Hash)

    a customizable set of options

Returns:

  • (Array, Hash, nil)


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/elasticsearch_record/relation/core_methods.rb', line 73

def msearch(items = nil, opts = {})
  # prevent query on +NullRelation+!
  return nil if null_relation? && !opts[:keep_null_relation]

  # check if values are provided, if not we use the arel from the current relation-scope
  arels = if items.nil?
            [arel]
          else
            # spawn a new relation to the block and maps each arel-object
            items.map { |value| yield(spawn, value).arel }
          end

  # check provided resolve method
  responses = if opts[:resolve]
                klass._query_by_msearch(arels).map(&opts[:resolve].to_sym)
              else
                klass._query_by_msearch(arels)
              end

  if opts[:transpose]
    [items, responses].transpose.to_h
  else
    responses
  end
end

#ordered_relationObject

overwrite original methods to provide a elasticsearch version: checks against the +#access_id_fielddata?+ to ensure the Elasticsearch Cluster allows access on the +_id+ field.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/elasticsearch_record/relation/core_methods.rb', line 101

def ordered_relation
  # order values already exist
  return self unless order_values.empty?

  # resolve valid primary_key
  # - either it is NOT the '_id' column
  # OR
  # - it is the '_id'-column, but +access_id_fielddata?+ is also enabled!
  valid_primary_key = if primary_key != '_id' || klass.connection.access_id_fielddata?
                        primary_key
                      else
                        nil
                      end

  # slightly changed original methods content
  if implicit_order_column || valid_primary_key
    # order by +implicit_order_column+ AND +primary_key+
    if implicit_order_column && valid_primary_key && implicit_order_column != valid_primary_key
      order(table[implicit_order_column].asc, table[valid_primary_key].asc)
    else
      order(table[implicit_order_column || valid_primary_key].asc)
    end
  else
    # order is not possible due restricted settings
    self
  end
end

#resolve(name = 'Load') ⇒ ElasticsearchRecord::Result

transforms the current relation into arel, compiles it to query and executes the query. returns the result object.

PLEASE NOTE: This makes the query +immutable+ and raises a +ActiveRecord::ImmutableRelation+ if you try to change it's values.

PLEASE NOTE: resolving records (instantiate) is never possible after calling this method!

Parameters:

  • name (String) (defaults to: 'Load')
    • custom instrumentation name (default: 'Load')

Returns:



20
21
22
23
24
# File 'lib/elasticsearch_record/relation/core_methods.rb', line 20

def resolve(name = 'Load')
  # this acts the same like +#_query_by_sql+ but we can customize the instrumentation name and
  # do not store the records.
  klass.connection.select_all(arel, "#{klass.name} #{name}")
end

#reverse_sql_order(order_query) ⇒ Object

overwrite original methods to provide a elasticsearch version: checks against the +#access_id_fielddata?+ to ensure the Elasticsearch Cluster allows access on the +_id+ field.



131
132
133
134
135
136
137
138
139
# File 'lib/elasticsearch_record/relation/core_methods.rb', line 131

def reverse_sql_order(order_query)
  if order_query.empty?
    return [table[primary_key].desc] if primary_key != '_id' || klass.connection.access_id_fielddata?
    raise ActiveRecord::IrreversibleOrderError,
          "Relation has no current order and fielddata access on the _id field is disallowed! However, you can re-enable it by updating the dynamic cluster setting: indices.id_field_data.enabled"
  end

  super
end

#to_queryHash

returns the query hash for the current relation

Returns:

  • (Hash)


28
29
30
# File 'lib/elasticsearch_record/relation/core_methods.rb', line 28

def to_query
  to_sql.query_arguments
end