mongodb_meilisearch 1.1.0 → 1.2.1
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/CHANGELOG.md +49 -0
- data/Gemfile.lock +1 -1
- data/README.md +34 -10
- data/lib/mongodb_meilisearch/version.rb +1 -1
- data/lib/search/class_methods.rb +36 -13
- data/lib/search/client.rb +1 -1
- data/lib/search/instance_methods.rb +11 -4
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8dcda2174ac28dc1b3e134d90d2fc92b2d43e6815cab31dfc8a2c8954939d658
|
4
|
+
data.tar.gz: 45b658a38a761d8c02bc1ee4d21f82d7762a60e749ba14b8ec53e987284bdc4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 425ebd155ffec9c67e96cbb8b028be16a27948566d8cd5e64bfb4226a9a3d89551a449cad2bc9c8ecb6dd2261cab702fdf426c603c82a5402d7660de90596149
|
7
|
+
data.tar.gz: 322b9b928ea51c65df41906e872c9497af27b8cda2b2e04e0f1d360348c6ed9d4e7ebfad731d6e97956fa4d3cf0eb3b7b686db8352fcd2285be984690138eade
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,52 @@
|
|
1
|
+
## [1.2.0] - 2024-06-19
|
2
|
+
|
3
|
+
### Features
|
4
|
+
- The value of `SEARCHABLE_ATTRIBUTES` can now optionally
|
5
|
+
include method names, not just field names.
|
6
|
+
|
7
|
+
This makes for easier incorporation of dynamically generated index values,
|
8
|
+
because it eliminates many cases where you would have had to define
|
9
|
+
a `search_indexable_hash` method. If you already have one, it'll
|
10
|
+
continue to work.
|
11
|
+
|
12
|
+
## [1.1.1] 2023-11-13
|
13
|
+
bug fix
|
14
|
+
|
15
|
+
### Fixes
|
16
|
+
|
17
|
+
Issue #7 - adding the first document from a new model didn't
|
18
|
+
configure the filterable attributes or searchable attributes.
|
19
|
+
The lack of the former would cause basic searches to fail
|
20
|
+
because of our expectation that "object_class" will always
|
21
|
+
be a filterable field unless you've specifically designated
|
22
|
+
your model as unfilterable.
|
23
|
+
|
24
|
+
|
25
|
+
## [1.1.0] - 2023-09-16
|
26
|
+
Sorting & Filtering
|
27
|
+
|
28
|
+
## Additions
|
29
|
+
- adds the ability to specify sortable attributes
|
30
|
+
- these default to match the filterable attributes
|
31
|
+
- filterable attributes still default to match
|
32
|
+
searchable attributes
|
33
|
+
- `set_filterable_attributes`
|
34
|
+
- `set_sortable_attributes`
|
35
|
+
- `set_sortable_attributes!`
|
36
|
+
- `reindex` and `reindex!` now set searchable attributes
|
37
|
+
|
38
|
+
## Fixes
|
39
|
+
- `set_filterable_attributes!` is now synchronous as the name implies
|
40
|
+
- `reindex_core` correctly honors the user's async request when
|
41
|
+
setting filterable attributes (previously it was always async)
|
42
|
+
|
43
|
+
## [1.0.1] - 2023-09-2
|
44
|
+
|
45
|
+
ids from `belongs_to` relations are no longer
|
46
|
+
indexed by default. You can explicitly specify
|
47
|
+
their inclusion if you want.
|
48
|
+
|
49
|
+
|
1
50
|
## [1.0.0] - 2023-07-22
|
2
51
|
|
3
52
|
- Initial release
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -169,16 +169,19 @@ unless you intend to allow users to sort by when a record was created,
|
|
169
169
|
there's no point in recording it's `created_at` in the search index.
|
170
170
|
It'll just waste bandwidth, memory, and disk space.
|
171
171
|
|
172
|
-
Define a `SEARCHABLE_ATTRIBUTES` constant with an array of strings to limit things.
|
173
|
-
|
174
|
-
|
172
|
+
Define a `SEARCHABLE_ATTRIBUTES` constant with an array of strings to limit things.
|
173
|
+
These are the field names, and/or names of methods you wish to have indexed.
|
174
|
+
|
175
|
+
By default these will _also_ be the fields you can filter on.
|
176
|
+
|
177
|
+
Note that Meilisearch requires there to be an `id` field and it must be a string.
|
175
178
|
If you don't define one it will use string version of the `_id` your
|
176
179
|
document's `BSON::ObjectId`.
|
177
180
|
|
178
181
|
```ruby
|
179
182
|
# explicitly define the fields you want to be searchable
|
180
183
|
# this should be an array of symbols
|
181
|
-
SEARCHABLE_ATTRIBUTES = %
|
184
|
+
SEARCHABLE_ATTRIBUTES = %w[title body]
|
182
185
|
# OR explicitly define the fields you DON'T want searchable
|
183
186
|
SEARCHABLE_ATTRIBUTES = searchable_attributes - [:created_at]
|
184
187
|
```
|
@@ -194,9 +197,16 @@ exclude any fields that are `Mongoid::Fields::ForeignKey` objects.
|
|
194
197
|
|
195
198
|
#### Getting Extra Specific
|
196
199
|
If your searchable data needs to by dynamically generated instead of
|
197
|
-
just taken directly from the `Mongoid::Document`'s attributes
|
198
|
-
define a `search_indexable_hash` method on your class.
|
199
|
-
|
200
|
+
just taken directly from the `Mongoid::Document`'s attributes or
|
201
|
+
existing methods you can define a `search_indexable_hash` method on your class.
|
202
|
+
|
203
|
+
Before you do, please note that as of v1.1 your `SEARCHABLE_ATTRIBUTES`
|
204
|
+
constant can contain fields and method names in its array of values. Making
|
205
|
+
a method for each thing dynamically generated thing you want in the search
|
206
|
+
and then including it in SEARCHABLE_ATTRIBUTES is going to be
|
207
|
+
the easiest way of accomplishing this.
|
208
|
+
|
209
|
+
Your `search_indexable_hash` must return a hash, and that hash must include the following keys:
|
200
210
|
- `"id"` - a string that uniquely identifies the record
|
201
211
|
- `"object_class"` the name of the class that this record corresponds to.
|
202
212
|
|
@@ -323,6 +333,16 @@ Be careful to not add documents that are already in the index.
|
|
323
333
|
WARNING: if you think you should use this, you're probably
|
324
334
|
mistaken.
|
325
335
|
|
336
|
+
#### Indexes
|
337
|
+
By default every model gets its own search index. This means that
|
338
|
+
`Foo.search("some text")` will only search `Foo` objects. To have a
|
339
|
+
search cross objects you'll need to use a "Shared Index" (see below).
|
340
|
+
|
341
|
+
|
342
|
+
The name of the index isn't important when not using shared indexes.
|
343
|
+
By default a model's index is the snake cased form of the class name.
|
344
|
+
For example, data for `MyWidget` models will be stored in the `my_widget` index.
|
345
|
+
|
326
346
|
#### Shared indexes
|
327
347
|
Imagine you have a `Note` and a `Comment` model, sharing an index so that
|
328
348
|
you can perform a single search and have search results for both models
|
@@ -442,10 +462,14 @@ To invoke any of Meilisearch's custom search options (see [their documentation](
|
|
442
462
|
|
443
463
|
`MyModel.search("search term", options: <my custom options>)`
|
444
464
|
|
445
|
-
|
465
|
+
Currently the Meilisearch-ruby gem can convert keys from snake case to
|
446
466
|
camel case. For example `hits_per_page` will become `hitsPerPage`.
|
447
|
-
Meilisearch ultimately wants camel case
|
448
|
-
|
467
|
+
Meilisearch ultimately wants camel case (`camelCase`) parameter keys,
|
468
|
+
_but_ `meilisearch-ruby` wants snake case (`snake_case`).
|
469
|
+
|
470
|
+
Follow Meilisearch's documentation
|
471
|
+
to see what's available and what type of options to pass it, but convert
|
472
|
+
them to snake case first. Note that your
|
449
473
|
options keys and values must all be simple JSON values.
|
450
474
|
|
451
475
|
If for some reason that still isn't enough, you can work with the
|
data/lib/search/class_methods.rb
CHANGED
@@ -109,6 +109,7 @@ module Search
|
|
109
109
|
# @param filtered_by_class [Boolean] - defaults to filtering results by the class
|
110
110
|
# your searching from. Ex. Foo.search("something") it will
|
111
111
|
# have Meilisearch filter on records where `object_class` == `"Foo"`
|
112
|
+
# This simplifies working with shared indexes.
|
112
113
|
# @return [Hash[String, [Array[String | Document]] a hash with keys corresponding
|
113
114
|
# to the classes of objects returned, and a value of an array of ids or
|
114
115
|
# Mongoid::Document objects sorted by match strength. It will ALSO have a key named
|
@@ -135,13 +136,13 @@ module Search
|
|
135
136
|
|
136
137
|
# TODO: break this if/else out into a separate function
|
137
138
|
if ids_only
|
138
|
-
options.merge!({
|
139
|
+
options.merge!({attributes_to_retrieve: [pk.to_s]})
|
139
140
|
else
|
140
141
|
# Don't care what you add, but we need the primary key and object_class
|
141
|
-
options[:
|
142
|
+
options[:attributes_to_retrieve] = [] unless options.has_key?(:attributes_to_retrieve)
|
142
143
|
[pk.to_s, "object_class"].each do |attr|
|
143
|
-
unless options[:
|
144
|
-
options[:
|
144
|
+
unless options[:attributes_to_retrieve].include?(attr)
|
145
|
+
options[:attributes_to_retrieve] << attr
|
145
146
|
end
|
146
147
|
end
|
147
148
|
end
|
@@ -260,6 +261,7 @@ module Search
|
|
260
261
|
# - each document hash is presumed to have been created by way of
|
261
262
|
# search_indexable_hash
|
262
263
|
def add_documents(new_documents, async: true)
|
264
|
+
configure_attributes_and_index_if_needed!
|
263
265
|
if async
|
264
266
|
search_index.add_documents(new_documents, primary_search_key)
|
265
267
|
else
|
@@ -393,17 +395,38 @@ module Search
|
|
393
395
|
# @return [Array] - an array of attributes configured as sortable
|
394
396
|
# in the index.
|
395
397
|
def meilisearch_sortable_attributes
|
396
|
-
|
397
|
-
search_index.http_get(
|
398
|
-
"/indexes/#{search_index}/settings/sortable-attributes"
|
399
|
-
)
|
398
|
+
@_meilisearch_sortable_attributes ||= search_index.get_sortable_attributes
|
400
399
|
end
|
401
400
|
|
402
401
|
def meilisearch_filterable_attributes
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
402
|
+
@_meilisearch_filterable_attributes ||= search_index.get_filterable_attributes
|
403
|
+
end
|
404
|
+
|
405
|
+
def reset_cached_data!
|
406
|
+
@_meilisearch_filterable_attributes = nil
|
407
|
+
@_filterable_attributes = nil
|
408
|
+
@_meilisearch_sortable_attributes = nil
|
409
|
+
@_sortable_attributes = nil
|
410
|
+
end
|
411
|
+
|
412
|
+
# Guarantees that the filterable attributes have been configured
|
413
|
+
# This should be called before
|
414
|
+
def configure_attributes_and_index_if_needed!
|
415
|
+
return if unfilterable?
|
416
|
+
indexes_filterable_attributes = []
|
417
|
+
|
418
|
+
begin
|
419
|
+
indexes_filterable_attributes = meilisearch_filterable_attributes
|
420
|
+
rescue ::MeiliSearch::ApiError => e
|
421
|
+
# this is expected to happen the first time an instance
|
422
|
+
# of a new model is saved.
|
423
|
+
raise unless e.message.match?(/Index `\S+` not found\./)
|
424
|
+
Search::Client.instance.create_index(search_index_name)
|
425
|
+
end
|
426
|
+
|
427
|
+
return if indexes_filterable_attributes.include?("object_class")
|
428
|
+
set_filterable_attributes
|
429
|
+
set_sortable_attributes
|
407
430
|
end
|
408
431
|
|
409
432
|
# Updates the filterable attributes in the search index.
|
@@ -579,7 +602,7 @@ module Search
|
|
579
602
|
def reindex_core(async: true)
|
580
603
|
# no point in continuing if this fails...
|
581
604
|
delete_all_documents!
|
582
|
-
|
605
|
+
reset_cached_data!
|
583
606
|
# this conveniently lines up with the batch size of 100
|
584
607
|
# that Mongoid gives us
|
585
608
|
documents = []
|
data/lib/search/client.rb
CHANGED
@@ -2,6 +2,7 @@ module Search
|
|
2
2
|
module InstanceMethods
|
3
3
|
# Adds this record to the search index asynchronously
|
4
4
|
def add_to_search
|
5
|
+
self.class.configure_attributes_and_index_if_needed!
|
5
6
|
search_index.add_documents(
|
6
7
|
[search_indexable_hash],
|
7
8
|
primary_search_key.to_s
|
@@ -10,6 +11,7 @@ module Search
|
|
10
11
|
|
11
12
|
# Adds this record to the search index synchronously
|
12
13
|
def add_to_search!
|
14
|
+
self.class.configure_attributes_and_index_if_needed!
|
13
15
|
index = search_index
|
14
16
|
documents = [search_indexable_hash]
|
15
17
|
pk = primary_search_key.to_s
|
@@ -42,6 +44,10 @@ module Search
|
|
42
44
|
search_index.delete_document!(send(primary_search_key).to_s)
|
43
45
|
end
|
44
46
|
|
47
|
+
def searchable_attributes
|
48
|
+
self.class.searchable_attributes
|
49
|
+
end
|
50
|
+
|
45
51
|
# returns a hash of all the attributes
|
46
52
|
# if searchable_attributes method is defined
|
47
53
|
# it is assumed to return a list of symbols
|
@@ -55,9 +61,10 @@ module Search
|
|
55
61
|
# in returned results
|
56
62
|
def search_indexable_hash
|
57
63
|
klass = self.class
|
58
|
-
|
59
|
-
|
60
|
-
|
64
|
+
# the to_s & to_sym is just safety in case someone
|
65
|
+
# defined searchable_attributes as an array of strings
|
66
|
+
hash = {}
|
67
|
+
searchable_attributes.each { |a| hash[a.to_s] = send(a.to_sym) }
|
61
68
|
|
62
69
|
# Meilisearch doesn't like a primary key of _id
|
63
70
|
# but Mongoid ids are _id
|
@@ -67,7 +74,7 @@ module Search
|
|
67
74
|
id = hash.delete("_id").to_s
|
68
75
|
new_id = (!klass.has_class_prefixed_search_ids?) ? id : "#{self.class.name}_#{id}"
|
69
76
|
hash["id"] = new_id
|
70
|
-
elsif hash.has_key?("id") && !hash[id].is_a?(String)
|
77
|
+
elsif hash.has_key?("id") && !hash["id"].is_a?(String)
|
71
78
|
# this is mostly in case it's a BSON::ObjectId
|
72
79
|
hash["id"] = hash["id"].to_s
|
73
80
|
elsif !hash.has_key?("id")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongodb_meilisearch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- masukomi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-06-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -187,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
187
187
|
- !ruby/object:Gem::Version
|
188
188
|
version: '0'
|
189
189
|
requirements: []
|
190
|
-
rubygems_version: 3.4.
|
190
|
+
rubygems_version: 3.4.20
|
191
191
|
signing_key:
|
192
192
|
specification_version: 4
|
193
193
|
summary: MeiliSearch integration for MongoDB
|