Module: SearchFlip::Filterable

Included in:
Aggregation, Criteria
Defined in:
lib/search_flip/filterable.rb

Overview

The SearchFlip::Filterable mixin provides chainable methods like #where, #exists, #range, etc to add search filters to a criteria.

Examples:

CommentIndex.where(public: true)
CommentIndex.exists(:user_id)
CommentIndex.range(:created_at, gt: Date.today - 7)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



12
13
14
15
16
# File 'lib/search_flip/filterable.rb', line 12

def self.included(base)
  base.class_eval do
    attr_accessor :search_values, :must_values, :must_not_values, :should_values, :filter_values
  end
end

Instance Method Details

#exists(field) ⇒ SearchFlip::Criteria

Adds an exists filter to the criteria, which selects all documents for which the specified field has a non-null value.

Examples:

CommentIndex.exists(:notified_at)

Parameters:

  • field (Symbol, String)

    The field that should have a non-null value

Returns:



221
222
223
# File 'lib/search_flip/filterable.rb', line 221

def exists(field)
  filter exists: { field: field }
end

#exists_not(field) ⇒ SearchFlip::Criteria

Adds an exists not filter to the criteria, which selects all documents for which the specified field’s value is null.

Examples:

CommentIndex.exists_not(:notified_at)

Parameters:

  • field (Symbol, String)

    The field that should have a null value

Returns:



235
236
237
# File 'lib/search_flip/filterable.rb', line 235

def exists_not(field)
  must_not exists: { field: field }
end

#filter(*args) ⇒ SearchFlip::Criteria

Adds raw filter queries to the criteria.

Examples:

CommentIndex.filter(term: { state: "new" })
CommentIndex.filter(range: { created_at: { gte: Time.parse("2016-01-01") }})

Parameters:

  • args (Array, Hash)

    The raw filter query arguments

Returns:



110
111
112
113
114
# File 'lib/search_flip/filterable.rb', line 110

def filter(*args)
  fresh.tap do |criteria|
    criteria.filter_values = (filter_values || []) + args
  end
end

#match_all(options = {}) ⇒ SearchFlip::Criteria

Adds a match all filter/query to the criteria, which simply matches all documents. This can be eg be used within filter aggregations or for filter chaining. Check out the ElasticSearch docs for further details.

Examples:

Basic usage

CommentIndex.match_all

Filter chaining

query = CommentIndex.match_all
query = query.where(public: true) unless current_user.admin?

Filter aggregation

query = CommentIndex.aggregate(filtered_tags: {}) do |aggregation|
  aggregation = aggregation.match_all
  aggregation = aggregation.where(user_id: current_user.id) if current_user
  aggregation = aggregation.aggregate(:tags)
end

query.aggregations(:filtered_tags).tags.buckets.each { ... }

Parameters:

  • options (Hash) (defaults to: {})

    Options for the match_all filter, like eg boost

Returns:



207
208
209
# File 'lib/search_flip/filterable.rb', line 207

def match_all(options = {})
  filter match_all: options
end

#must(*args) ⇒ SearchFlip::Criteria

Adds raw must queries to the criteria.

Examples:

CommentIndex.must(term: { state: "new" })
CommentIndex.must(range: { created_at: { gt: Time.parse("2016-01-01") }})

Parameters:

  • args (Array, Hash)

    The raw must query arguments

Returns:



126
127
128
129
130
# File 'lib/search_flip/filterable.rb', line 126

def must(*args)
  fresh.tap do |criteria|
    criteria.must_values = (must_values || []) + args
  end
end

#must_not(*args) ⇒ SearchFlip::Criteria

Adds raw must_not queries to the criteria.

Examples:

CommentIndex.must_not(term: { state: "new" })
CommentIndex.must_not(range: { created_at: { gt: Time.parse"2016-01-01") }})

Parameters:

  • args (Array, Hash)

    The raw must_not query arguments

Returns:



142
143
144
145
146
# File 'lib/search_flip/filterable.rb', line 142

def must_not(*args)
  fresh.tap do |criteria|
    criteria.must_not_values = (must_not_values || []) + args
  end
end

#range(field, options = {}) ⇒ SearchFlip::Criteria

Adds a range filter to the criteria without being forced to specify the left and right end of the range, such that you can eg simply specify lt, lte, gt and gte. For fully specified ranges, you can as well use #where, etc. Check out the ElasticSearch docs for further details regarding the range filter.

Examples:

CommentIndex.range(:created_at, gte: Time.parse("2016-01-01"))
CommentIndex.range(:likes_count, gt: 10, lt: 100)

Parameters:

  • field (Symbol, String)

    The field name to specify the range for

  • options (Hash) (defaults to: {})

    The range filter specification, like lt, lte, etc

Returns:



179
180
181
# File 'lib/search_flip/filterable.rb', line 179

def range(field, options = {})
  filter range: { field => options }
end

#search(q, options = {}) ⇒ SearchFlip::Criteria

Adds a query string query to the criteria while using AND as the default operator unless otherwise specified. Check out the ElasticSearch docs for further details.

Examples:

CommentIndex.search("message:hello OR message:worl*")

Parameters:

  • q (String)

    The query string query

  • options (Hash) (defaults to: {})

    Additional options for the query string query, like eg default_operator, default_field, etc.

Returns:



32
33
34
35
36
# File 'lib/search_flip/filterable.rb', line 32

def search(q, options = {})
  fresh.tap do |criteria|
    criteria.search_values = (search_values || []) + [query_string: { query: q, :default_operator => :AND }.merge(options)] if q.to_s.strip.length > 0
  end
end

#should(*args) ⇒ SearchFlip::Criteria

Adds raw should queries to the criteria.

Examples:

CommentIndex.should(term: { state: "new" })
CommentIndex.should(range: { created_at: { gt: Time.parse"2016-01-01") }})

Parameters:

  • args (Array, Hash)

    The raw should query arguments

Returns:



158
159
160
161
162
# File 'lib/search_flip/filterable.rb', line 158

def should(*args)
  fresh.tap do |criteria|
    criteria.should_values = (should_values || []) + args
  end
end

#where(hash) ⇒ SearchFlip::Criteria

Adds filters to your criteria for the supplied hash composed of field-to-filter mappings which specify terms, term or range filters, depending on the type of the respective hash value, namely array, range or scalar type like Fixnum, String, etc.

Examples:

CommentIndex.where(id: [1, 2, 3], state: ["approved", "declined"])
CommentIndex.where(id: 1 .. 100)
CommentIndex.where(created_at: Time.parse("2016-01-01") .. Time.parse("2017-01-01"))
CommentIndex.where(id: 1, message: "hello")
CommentIndex.where(state: nil)

Parameters:

  • hash (Hash)

    A field-to-filter mapping specifying filter values for the respective fields

Returns:



55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/search_flip/filterable.rb', line 55

def where(hash)
  hash.inject(fresh) do |memo, (key, value)|
    if value.is_a?(Array)
      memo.filter terms: { key => value }
    elsif value.is_a?(Range)
      memo.filter range: { key => { gte: value.min, lte: value.max } }
    elsif value.nil?
      memo.exists_not key
    else
      memo.filter term: { key => value }
    end
  end
end

#where_not(hash) ⇒ SearchFlip::Criteria

Adds filters to exclude documents in accordance to the supplied hash composed of field-to-filter mappings. Check out #where for further details.

Examples:

CommentIndex.where_not(state: "approved")
CommentIndex.where_not(created_at: Time.parse("2016-01-01") .. Time.parse("2017-01-01"))
CommentIndex.where_not(id: [1, 2, 3], state: "new")
CommentIndex.where_not(state: nil)

Parameters:

  • hash (Hash)

    A field-to-filter mapping specifying filter values for the respective fields

Returns:

See Also:



86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/search_flip/filterable.rb', line 86

def where_not(hash)
  hash.inject(fresh) do |memo, (key, value)|
    if value.is_a?(Array)
      memo.must_not terms: { key => value }
    elsif value.is_a?(Range)
      memo.must_not range: { key => { gte: value.min, lte: value.max } }
    elsif value.nil?
      memo.exists key
    else
      memo.must_not term: { key => value }
    end
  end
end