mongoid_search 0.3.5 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +26 -1
- data/VERSION +1 -1
- data/lib/mongoid_search.rb +1 -1
- data/lib/mongoid_search/mongoid_search.rb +28 -11
- data/spec/models/product.rb +3 -0
- data/spec/models/variant.rb +2 -0
- data/spec/mongoid_search_spec.rb +21 -5
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65d13fcd90c890df7b15f2175b701e951259f8de
|
4
|
+
data.tar.gz: '097843e60c25fc38ddb96789093dc798a08c5739'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a13b1d7f1bce08ffed931346ec1b1b6750ad984aeb263d93fc1c1db3dd8d03761a763958fb8d000ec19b0ea98b791e3d15020cd152375dbc5d5e19338cc5944f
|
7
|
+
data.tar.gz: 71008ecd40e79df705f769d03e0b03953a3278b3cb46ceb325b212e48b8c1321c58aa540750b094d8a94cc9082cbd66e13bba145ebfc7c0af6f78ce7a72fa796
|
data/README.md
CHANGED
@@ -26,12 +26,14 @@ class Product
|
|
26
26
|
include Mongoid::Search
|
27
27
|
field :brand
|
28
28
|
field :name
|
29
|
+
field :unit
|
29
30
|
field :info, type: Hash
|
30
31
|
|
31
32
|
has_many :tags
|
32
33
|
belongs_to :category
|
33
34
|
|
34
35
|
search_in :brand, :name, tags: :name, category: :name, info: %i[summary description]
|
36
|
+
search_in :unit, index: :_unit_keywords
|
35
37
|
end
|
36
38
|
|
37
39
|
class Tag
|
@@ -52,7 +54,7 @@ end
|
|
52
54
|
Now when you save a product, you get a `_keywords` field automatically:
|
53
55
|
|
54
56
|
```ruby
|
55
|
-
p = Product.new brand: 'Apple', name: 'iPhone', info: { summary: 'Info-summary', description: 'Info-description' }
|
57
|
+
p = Product.new brand: 'Apple', name: 'iPhone', unit: 'kilogram', info: { summary: 'Info-summary', description: 'Info-description' }
|
56
58
|
p.tags << Tag.new(name: 'Amazing')
|
57
59
|
p.tags << Tag.new(name: 'Awesome')
|
58
60
|
p.tags << Tag.new(name: 'Superb')
|
@@ -60,6 +62,8 @@ p.save
|
|
60
62
|
# => true
|
61
63
|
p._keywords
|
62
64
|
# => ["amazing", "apple", "awesome", "iphone", "superb", "Info-summary", "Info-description"]
|
65
|
+
p._unit_keywords
|
66
|
+
# => ["kilogram"]
|
63
67
|
```
|
64
68
|
|
65
69
|
Now you can run search, which will look in the `_keywords` field and return all matching results:
|
@@ -69,6 +73,13 @@ Product.full_text_search("apple iphone").size
|
|
69
73
|
# => 1
|
70
74
|
```
|
71
75
|
|
76
|
+
Of course, some models could have more than one index. For instance, two different searches with different fields, so you could even specify from which index should be searched:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
Product.full_text_search("kilogram", index: :_unit_keywords).size
|
80
|
+
# => 1
|
81
|
+
```
|
82
|
+
|
72
83
|
Note that the search is case insensitive, and accept partial searching too:
|
73
84
|
|
74
85
|
```ruby
|
@@ -131,6 +142,20 @@ Product.full_text_search('amazing apple', relevant_search: true)
|
|
131
142
|
|
132
143
|
Please note that relevant_search will return an Array and not a Criteria object. The search method should always be called in the end of the method chain.
|
133
144
|
|
145
|
+
### index
|
146
|
+
|
147
|
+
Default is `_keywords`.
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
Product.full_text_search('amazing apple', index: :_keywords)
|
151
|
+
# => [#<Product _id: 5016e7d16af54efe1c000001, _type: nil, brand: "Apple", name: "iPhone", unit: "l", attrs: nil, info: nil, category_id: nil, _keywords: ["amazing", "apple", "awesome", "iphone", "superb"], _unit_keywords: ["l"], relevance: 2.0>]
|
152
|
+
|
153
|
+
Product.full_text_search('kg', index: :_unit_keywords)
|
154
|
+
# => [#<Product _id: 5016e7d16af54efe1c000001, _type: nil, brand: "Apple", name: "iPhone", unit: "kg", attrs: nil, info: nil, category_id: nil, _keywords: ["amazing", "apple", "awesome", "iphone", "superb"], _unit_keywords: ["kg"], relevance: 2.0>]
|
155
|
+
```
|
156
|
+
|
157
|
+
index enables to have two or more different searches, with different or same fields. It should be noted that indexes are exclusive per each one.
|
158
|
+
|
134
159
|
## Initializer
|
135
160
|
|
136
161
|
Alternatively, you can create an initializer to setup those options:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.6
|
data/lib/mongoid_search.rb
CHANGED
@@ -50,7 +50,7 @@ module Mongoid::Search
|
|
50
50
|
# Ligatures to be replaced
|
51
51
|
# http://en.wikipedia.org/wiki/Typographic_ligature
|
52
52
|
mattr_accessor :ligatures
|
53
|
-
@@ligatures = { 'œ' => 'oe', 'æ' => 'ae' }
|
53
|
+
@@ligatures = { 'œ' => 'oe', 'æ' => 'ae', 'ꜵ' => 'ao' }
|
54
54
|
|
55
55
|
# Minimum word size. Words smaller than it won't be indexed
|
56
56
|
mattr_accessor :minimum_word_size
|
@@ -14,12 +14,12 @@ module Mongoid::Search
|
|
14
14
|
module ClassMethods #:nodoc:
|
15
15
|
# Set a field or a number of fields as sources for search
|
16
16
|
def search_in(*args)
|
17
|
-
args,
|
18
|
-
|
17
|
+
args, options = args_and_options(args)
|
18
|
+
set_search_fields(options[:index], args)
|
19
19
|
|
20
|
-
field :
|
20
|
+
field options[:index], type: Array
|
21
21
|
|
22
|
-
index({
|
22
|
+
index({ options[:index] => 1 }, background: true)
|
23
23
|
|
24
24
|
before_save :set_keywords
|
25
25
|
end
|
@@ -49,13 +49,20 @@ module Mongoid::Search
|
|
49
49
|
|
50
50
|
private
|
51
51
|
|
52
|
+
def set_search_fields(index, fields)
|
53
|
+
self.search_fields ||= {}
|
54
|
+
|
55
|
+
(self.search_fields[index] ||= []).concat fields
|
56
|
+
end
|
57
|
+
|
52
58
|
def query(keywords, options)
|
53
59
|
keywords_hash = keywords.map do |kw|
|
54
60
|
if Mongoid::Search.regex_search
|
55
61
|
escaped_kw = Regexp.escape(kw)
|
56
62
|
kw = Mongoid::Search.regex.call(escaped_kw)
|
57
63
|
end
|
58
|
-
|
64
|
+
|
65
|
+
{ options[:index] => kw }
|
59
66
|
end
|
60
67
|
|
61
68
|
criteria.send("#{(options[:match])}_of", *keywords_hash)
|
@@ -65,6 +72,7 @@ module Mongoid::Search
|
|
65
72
|
options = args.last.is_a?(Hash) &&
|
66
73
|
%i[match
|
67
74
|
allow_empty_search
|
75
|
+
index
|
68
76
|
relevant_search].include?(args.last.keys.first) ? args.pop : {}
|
69
77
|
|
70
78
|
[args, extract_options(options)]
|
@@ -74,7 +82,8 @@ module Mongoid::Search
|
|
74
82
|
{
|
75
83
|
match: options[:match] || Mongoid::Search.match,
|
76
84
|
allow_empty_search: options[:allow_empty_search] || Mongoid::Search.allow_empty_search,
|
77
|
-
relevant_search: options[:relevant_search] || Mongoid::Search.relevant_search
|
85
|
+
relevant_search: options[:relevant_search] || Mongoid::Search.relevant_search,
|
86
|
+
index: options[:index] || :_keywords
|
78
87
|
}
|
79
88
|
end
|
80
89
|
|
@@ -99,8 +108,8 @@ module Mongoid::Search
|
|
99
108
|
function() {
|
100
109
|
var entries = 0;
|
101
110
|
for(i in keywords) {
|
102
|
-
for(j in this
|
103
|
-
if(this
|
111
|
+
for(j in this.#{options[:index]}) {
|
112
|
+
if(this.#{options[:index]}[j] == keywords[i]) {
|
104
113
|
entries++;
|
105
114
|
}
|
106
115
|
}
|
@@ -122,11 +131,19 @@ module Mongoid::Search
|
|
122
131
|
end
|
123
132
|
|
124
133
|
def index_keywords!
|
125
|
-
|
134
|
+
search_fields.map do |index, fields|
|
135
|
+
update_attribute(index, get_keywords(fields))
|
136
|
+
end
|
126
137
|
end
|
127
138
|
|
128
139
|
def set_keywords
|
129
|
-
|
130
|
-
|
140
|
+
search_fields.each do |index, fields|
|
141
|
+
send("#{index}=", get_keywords(fields))
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def get_keywords(fields)
|
146
|
+
Mongoid::Search::Util.keywords(self, fields)
|
147
|
+
.flatten.reject { |k| k.nil? || k.empty? }.uniq.sort
|
131
148
|
end
|
132
149
|
end
|
data/spec/models/product.rb
CHANGED
@@ -5,6 +5,8 @@ class Product
|
|
5
5
|
|
6
6
|
field :brand
|
7
7
|
field :name
|
8
|
+
field :unit
|
9
|
+
field :measures, type: Array
|
8
10
|
field :attrs, type: Array
|
9
11
|
field :info, type: Hash
|
10
12
|
|
@@ -18,4 +20,5 @@ class Product
|
|
18
20
|
|
19
21
|
search_in :brand, :name, :outlet, :attrs, tags: :name, category: %i[name description],
|
20
22
|
subproducts: %i[brand name], info: %i[summary description]
|
23
|
+
search_in :unit, :measures, index: :_unit_keywords
|
21
24
|
end
|
data/spec/models/variant.rb
CHANGED
data/spec/mongoid_search_spec.rb
CHANGED
@@ -18,6 +18,7 @@ describe Mongoid::Search do
|
|
18
18
|
Mongoid::Search.stem_proc = @default_proc
|
19
19
|
@product = Product.create brand: 'Apple',
|
20
20
|
name: 'iPhone',
|
21
|
+
unit: 'mobile olé awesome',
|
21
22
|
tags: (@tags = %w[Amazing Awesome Olé].map { |tag| Tag.new(name: tag) }),
|
22
23
|
category: Category.new(name: 'Mobile', description: 'Reviews'),
|
23
24
|
subproducts: [Subproduct.new(brand: 'Apple', name: 'Craddle')],
|
@@ -52,6 +53,7 @@ describe Mongoid::Search do
|
|
52
53
|
Mongoid::Search.ignore_list = nil
|
53
54
|
@product = Product.create brand: 'Эльбрус',
|
54
55
|
name: 'Процессор',
|
56
|
+
unit: 'kílográm Olé',
|
55
57
|
tags: %w[Amazing Awesome Olé].map { |tag| Tag.new(name: tag) },
|
56
58
|
category: Category.new(name: 'процессоры'),
|
57
59
|
subproducts: []
|
@@ -59,10 +61,12 @@ describe Mongoid::Search do
|
|
59
61
|
|
60
62
|
it 'should leave utf8 characters' do
|
61
63
|
expect(@product._keywords).to eq %w[amazing awesome ole процессор процессоры эльбрус]
|
64
|
+
expect(@product._unit_keywords).to eq %w[kilogram ole]
|
62
65
|
end
|
63
66
|
|
64
67
|
it "should return results in search when case doesn't match" do
|
65
68
|
expect(Product.full_text_search('ЭЛЬБРУС').size).to eq 1
|
69
|
+
expect(Product.full_text_search('KILOGRAM', index: :_unit_keywords).size).to eq 1
|
66
70
|
end
|
67
71
|
end
|
68
72
|
|
@@ -74,15 +78,18 @@ describe Mongoid::Search do
|
|
74
78
|
end
|
75
79
|
|
76
80
|
it 'should validate keywords' do
|
77
|
-
product = Product.create brand: 'Apple', name: 'iPhone'
|
81
|
+
product = Product.create brand: 'Apple', name: 'iPhone', unit: 'box'
|
78
82
|
expect(product._keywords).to eq(%w[apple iphone])
|
83
|
+
expect(product._unit_keywords).to eq(%w[box])
|
79
84
|
end
|
80
85
|
end
|
81
86
|
|
82
87
|
it 'should set the _keywords field for array fields also' do
|
83
88
|
@product.attrs = ['lightweight', 'plastic', :red]
|
89
|
+
@product.measures = ['box', 'bunch', :bag]
|
84
90
|
@product.save!
|
85
91
|
expect(@product._keywords).to include 'lightweight', 'plastic', 'red'
|
92
|
+
expect(@product._unit_keywords).to include 'box', 'bunch', 'bag'
|
86
93
|
end
|
87
94
|
|
88
95
|
it 'should inherit _keywords field and build upon' do
|
@@ -91,39 +98,48 @@ describe Mongoid::Search do
|
|
91
98
|
tags: %w[Amazing Awesome Olé].map { |tag| Tag.new(name: tag) },
|
92
99
|
category: Category.new(name: 'Mobile'),
|
93
100
|
subproducts: [Subproduct.new(brand: 'Apple', name: 'Craddle')],
|
94
|
-
color: :white
|
101
|
+
color: :white,
|
102
|
+
size: :big
|
95
103
|
expect(variant._keywords).to include 'white'
|
104
|
+
expect(variant._unit_keywords).to include 'big'
|
96
105
|
expect(Variant.full_text_search(name: 'Apple', color: :white)).to eq [variant]
|
106
|
+
expect(Variant.full_text_search({ size: 'big' }, index: :_unit_keywords)).to eq [variant]
|
97
107
|
end
|
98
108
|
|
99
109
|
it 'should expand the ligature to ease searching' do
|
100
110
|
# ref: http://en.wikipedia.org/wiki/Typographic_ligature, only for french right now. Rules for other languages are not know
|
101
111
|
variant1 = Variant.create tags: ['œuvre'].map { |tag| Tag.new(name: tag) }
|
102
112
|
variant2 = Variant.create tags: ['æquo'].map { |tag| Tag.new(name: tag) }
|
113
|
+
variant3 = Variant.create measures: ['ꜵquo'].map { |measure| measure }
|
103
114
|
|
104
115
|
expect(Variant.full_text_search('œuvre')).to eq [variant1]
|
105
116
|
expect(Variant.full_text_search('oeuvre')).to eq [variant1]
|
106
117
|
expect(Variant.full_text_search('æquo')).to eq [variant2]
|
107
118
|
expect(Variant.full_text_search('aequo')).to eq [variant2]
|
119
|
+
expect(Variant.full_text_search('aoquo', index: :_unit_keywords)).to eq [variant3]
|
120
|
+
expect(Variant.full_text_search('ꜵquo', index: :_unit_keywords)).to eq [variant3]
|
108
121
|
end
|
109
122
|
|
110
|
-
it 'should set the
|
123
|
+
it 'should set the keywords fields with stemmed words if stem is enabled' do
|
111
124
|
Mongoid::Search.stem_keywords = true
|
112
125
|
@product.save!
|
113
126
|
expect(@product._keywords.sort).to eq %w[amaz appl awesom craddl iphon mobil review ol info descript summari].sort
|
127
|
+
expect(@product._unit_keywords.sort).to eq %w[mobil awesom ol].sort
|
114
128
|
end
|
115
129
|
|
116
|
-
it 'should set the
|
130
|
+
it 'should set the keywords fields with custom stemmed words if stem is enabled with a custom lambda' do
|
117
131
|
Mongoid::Search.stem_keywords = true
|
118
132
|
Mongoid::Search.stem_proc = proc { |word| word.upcase }
|
119
133
|
@product.save!
|
120
134
|
expect(@product._keywords.sort).to eq %w[AMAZING APPLE AWESOME CRADDLE DESCRIPTION INFO IPHONE MOBILE OLE REVIEWS SUMMARY]
|
135
|
+
expect(@product._unit_keywords.sort).to eq %w[AWESOME MOBILE OLE]
|
121
136
|
end
|
122
137
|
|
123
138
|
it 'should ignore keywords in an ignore list' do
|
124
139
|
Mongoid::Search.ignore_list = YAML.safe_load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))['ignorelist']
|
125
140
|
@product.save!
|
126
141
|
expect(@product._keywords.sort).to eq %w[apple craddle iphone mobile reviews ole info description summary].sort
|
142
|
+
expect(@product._unit_keywords.sort).to eq %w[mobile ole].sort
|
127
143
|
end
|
128
144
|
|
129
145
|
it 'should incorporate numbers as keywords' do
|
@@ -205,7 +221,7 @@ describe Mongoid::Search do
|
|
205
221
|
end
|
206
222
|
|
207
223
|
it 'should have a method to index keywords' do
|
208
|
-
expect(@product.index_keywords!).to
|
224
|
+
expect(@product.index_keywords!).to include(true)
|
209
225
|
end
|
210
226
|
|
211
227
|
it 'should have a class method to index all documents keywords' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mauricio Zaffari
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fast-stemmer
|
@@ -140,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
140
|
version: 1.3.6
|
141
141
|
requirements: []
|
142
142
|
rubyforge_project:
|
143
|
-
rubygems_version: 2.6.
|
143
|
+
rubygems_version: 2.6.14
|
144
144
|
signing_key:
|
145
145
|
specification_version: 4
|
146
146
|
summary: Search implementation for Mongoid ORM
|