• Stars
    star
    319
  • Rank 131,491 (Top 3 %)
  • Language
    Ruby
  • License
    MIT License
  • Created about 14 years ago
  • Updated 9 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Simple full text search for Mongoid ORM

Mongoid Search

Mongoid Search is a simple full text search implementation for Mongoid ORM. It supports Mongoid 3, 4, 5 and 6 and performs well for small data sets. If your searchable model is big (i.e. 1.000.000+ records), mongoid_fulltext, ElasticSearch, Solr or Sphinx may suit you better.

Build Status

Installation

In your Gemfile:

gem 'mongoid_search'

Then:

bundle install

Examples

class Product
  include Mongoid::Document
  include Mongoid::Search
  field :brand
  field :name
  field :unit
  field :info, type: Hash

  has_many   :tags
  belongs_to :category

  search_in :brand, :name, tags: :name, category: :name, info: %i[summary description]
  search_in :unit, index: :_unit_keywords
end

class Tag
  include Mongoid::Document
  field :name

  belongs_to :product
end

class Category
  include Mongoid::Document
  field :name

  has_many :products
end

Now when you save a product, you get a _keywords field automatically:

p = Product.new brand: 'Apple', name: 'iPhone', unit: 'kilogram', info: { summary: 'Info-summary', description: 'Info-description' }
p.tags << Tag.new(name: 'Amazing')
p.tags << Tag.new(name: 'Awesome')
p.tags << Tag.new(name: 'Superb')
p.save
# => true
p._keywords
# => ["amazing", "apple", "awesome", "iphone", "superb", "Info-summary", "Info-description"]
p._unit_keywords
# => ["kilogram"]

Now you can run search, which will look in the _keywords field and return all matching results:

Product.full_text_search("apple iphone").size
# => 1

You can also search in "virtual" fields by defining them as methods. This can be useful when you have a method with dynamic fields (i.e. variable schema).

class ModelWithDynamicFields
  
  ...
  
  search_in :search_data

  def search_data
    # concatenate all String fields' values
    self.attributes.select{|k,v| v.is_a?(String) }.values.join(' ')
  end
end

Mongoid_search will run the method before save and use it's output to populate the _keywords field.

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:

Product.full_text_search("kilogram", index: :_unit_keywords).size
# => 1

Note that the search is case insensitive, and accept partial searching too:

Product.full_text_search('ipho').size
# => 1

Assuming you have a category with multiple products you can use the following code to search for 'iphone' in products cheaper than $499.

category.products.where(:price.lt => 499).full_text_search('iphone').asc(:price)

To index or reindex all existing records, run this rake task

$ rake mongoid_search:index

Options

match

  • :any - match any occurrence
  • :all - match all occurrences

Default is :any.

Product.full_text_search('apple motorola', match: :any).size
# => 1

Product.full_text_search('apple motorola', match: :all).size
# => 0

allow_empty_search

  • true - will return Model.all
  • false - will return []

Default is false.

Product.full_text_search('', allow_empty_search: true).size
# => 1

relevant_search

  • true - adds relevance information to the results
  • false - no relevance information

Default is false.

Product.full_text_search('amazing apple', relevant_search: true)
# => [#<Product _id: 5016e7d16af54efe1c000001, _type: nil, brand: "Apple", name: "iPhone", attrs: nil, info: nil, category_id: nil, _keywords: ["amazing", "apple", "awesome", "iphone", "superb"], relevance: 2.0>]

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.

index

Default is _keywords.

Product.full_text_search('amazing apple', index: :_keywords)
# => [#<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>]

Product.full_text_search('kg', index: :_unit_keywords)
# => [#<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>]

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.

Initializer

Alternatively, you can create an initializer to setup those options:

Mongoid::Search.setup do |config|
  ## Default matching type. Match :any or :all searched keywords
  config.match = :any

  ## If true, an empty search will return all objects
  config.allow_empty_search = false

  ## If true, will search with relevance information
  config.relevant_search = false

  ## Stem keywords
  config.stem_keywords = false

  ## Add a custom proc returning strings to replace the default stemmer
  # For example using ruby-stemmer:
  # config.stem_proc = Proc.new { |word| Lingua.stemmer(word, :language => 'nl') }

  ## Words to ignore
  config.ignore_list = []

  ## An array of words
  # config.ignore_list = %w{ a an to from as }

  ## Or from a file
  # config.ignore_list = YAML.load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))["ignorelist"]

  ## Search using regex (slower)
  config.regex_search = true

  ## Regex to search

  ## Match partial words on both sides (slower)
  config.regex = Proc.new { |query| /#{query}/ }

  ## Match partial words on the beginning or in the end (slightly faster)
  # config.regex = Proc.new { |query| /^#{query}/ }
  # config.regex = Proc.new { |query| /#{query}$/ }

  # Ligatures to be replaced
  # http://en.wikipedia.org/wiki/Typographic_ligature
  config.ligatures = { "Ε“"=>"oe", "Γ¦"=>"ae" }

  # Strip symbols regex to be replaced. These symbols will be replaced by space
  config.strip_symbols = /[._:;'\"`,?|+={}()!@#%^&*<>~\$\-\\\/\[\]]/

  # Strip accents regex to be replaced. These sybols will be removed after strip_symbols replacing
  config.strip_accents = /[^\s\p{Alnum}]/

  # Minimum word size. Words smaller than it won't be indexed
  config.minimum_word_size = 2
end

More Repositories

1

mongoid-rspec

RSpec matchers and macros for Mongoid.
Ruby
498
star
2

mongoid-slug

Generates a URL slug/permalink based on fields in a Mongoid-based model.
Ruby
493
star
3

mongoid-history

Multi-user non-linear history tracking, auditing, undo, redo for mongoid.
Ruby
392
star
4

moped

A MongoDB driver for Ruby
Ruby
202
star
5

mongoid_fulltext

An n-gram-based full-text search implementation for the Mongoid ODM.
Ruby
150
star
6

mongoid-site

Source code for mongoid.org
HTML
141
star
7

echo

The Mongoid Demo Application
Ruby
128
star
8

mongoid_orderable

Acts as list mongoid implementation
Ruby
103
star
9

kiqstand

Mongoid 3 Middleware for Sidekiq
Ruby
97
star
10

mongoid-grid_fs

A pure Mongoid/Moped implementation of the MongoDB GridFS specification.
Ruby
83
star
11

mongoid-locker

Document-level locking for MongoDB via Mongoid
Ruby
77
star
12

mongoid-cached-json

Effective caching for nested JSON models.
Ruby
74
star
13

origin

A Ruby DSL for building MongoDB queries
Ruby
62
star
14

mongoid-scroll

Mongoid extension that enables infinite scrolling with MongoDB.
Ruby
60
star
15

mongo_session_store

MongoSessionStore is a Rails-compatible session store for MongoDB using either Mongoid or the MongoDB Ruby Driver. It also allows for custom Mongo session store that works with any (or no!) Mongo ODM
Ruby
56
star
16

evolver

Database Schema Evolution for MongoDB
Ruby
44
star
17

mongoid-demo

Demo applications for Mongoid
Ruby
19
star
18

mongoid-observers

Mongoid observer (removed in Mongoid 4.0)
Ruby
19
star
19

mongoid.github.io

Mongoid community site.
HTML
15
star
20

scooter

An Asynchronous (Non-Blocking) MongoDB driver for the JVM
Scala
15
star
21

mongoid-shell

Derive shell commands from Mongoid sessions and configuration options.
Ruby
14
star
22

moped-turbo

Moped turbocharger. (C extensions for Moped)
Ruby
13
star
23

mongoid-tag-collectible

Easily maintain a collection of Tag instances with aggregate counts from your model's tags.
Ruby
9
star
24

delayed_job_shallow_mongoid

When the object or arg to a delayed_job is a Mongoid document, store only a small stub of the object instead of the full serialization.
Ruby
8
star
25

echo-goliath

Simple Sample of Using Moped and Goliath.
Ruby
7
star
26

mongoid-compatibility

Compatibility helpers for the many Mongoid versions.
Ruby
7
star
27

scourge

1
star