Skip to content

Instantly share code, notes, and snippets.

@namxam
Created October 13, 2014 15:43
Show Gist options
  • Save namxam/33dca27bdcdb85c58486 to your computer and use it in GitHub Desktop.
Save namxam/33dca27bdcdb85c58486 to your computer and use it in GitHub Desktop.
Extract all fields from an elastic search model mapping and returns them in a format which can be used in queries
# A small elastic search extension to retrieve a list of all field names in a
# dot notation. This way we can directly use it in ES queries.
#
# Example:
#
# # in app/models/transaction.rb
# class Transaction < ActiveRecord::Base
# include ElasticSearch::FieldNames
# end
#
module ElasticSearch
module FieldNames
extend ActiveSupport::Concern
class MappingSchema
attr_accessor :klass
def initialize(klass)
self.klass = klass
end
def to_a
schema = only_properties(mapping_fields)
flattened_schema = dotify(schema)
end
def mapping_fields
@mapping_fields = klass.mapping.to_hash[klass.document_type.to_sym][:properties]
end
def dotify(data, key = '')
data.each_with_object([]) do |item, result|
case item
when Hash
result << item.map { |k, v| dotify(v, key + k.to_s + '.') }
when Array
result << item.map { |k| dotify(k, key) }
else
result << key + item.to_s
end
end.flatten
end
def only_properties(hash)
hash.map do |key, subhash|
if subhash.is_a?(Hash) && subhash.has_key?(:properties)
{ key => only_properties(subhash[:properties]) }
else
key
end
end
end
end
module ClassMethods
def es_field_names
@es_field_names ||= MappingSchema.new(self).to_a
end
end
end
end
require 'rails_helper'
RSpec.describe ElasticSearch::FieldNames do
class MyFieldNamesModel < ActiveRecord::Base
include Elasticsearch::Model
include ElasticSearch::FieldNames
settings do
mappings dynamic: 'false' do
indexes :name, type: 'string', index: 'not_analyzed'
indexes :account do
indexes :id, type: 'integer'
indexes :name, type: 'string'
indexes :owner do
indexes :name, type: 'string'
end
end
end
end
end
describe '.es_field_names' do
subject { MyFieldNamesModel }
it 'returns only strings' do
subject.es_field_names.each { |field| expect(field).to be_kind_of(String) }
end
it 'does not change first level attributes' do
expect(subject.es_field_names).to include('name')
end
it 'prefixes second level elements' do
expect(subject.es_field_names).to include('account.id')
end
it 'prefixes handles multiple second level elements' do
expect(subject.es_field_names).to include('account.id', 'account.name')
end
it 'works for deeply nested elements' do
expect(subject.es_field_names).to include('account.owner.name')
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment