Mongoid_Alphadog
A simple little gem that makes it easy to fetch a case-insensitive alphabetized list of Mongoid documents.
Problem
By design, MongoDB does not sort case-insensitive when sorting string fields. So objects with names like this:
['aardvark', 'Archie', 'banana', 'Checkers']
... will come out like this if you do order_by(:name)
['aardvark', 'banana', 'Archie', 'Checkers']
That's probably not what you're expecting, especially when using this on the front-end of your app.
Mongoid_Alphadog makes it easier and cleaner to solve this in your app using the oft-recommended workaround of a lowercased field.
Requirements
- MongoDB
- Mongoid
Installation
Add mongoid_alphadog to your Gemfile:
gem 'mongoid_alphadog'
IMPORTANT NOTE
Keep in mind that adding this to an existing app won't necessarily work immediately. Since alphadog does its magic on a before_save added to your model, you will want to make sure you re-save all the documents in collections to which you add Mongoid::Alphadog. Easy, not-necessarily-performant way:
Item.all.each{ |i| i.save }
Maybe someday I'll add a fancy rake task or something to help you alphadog-ify pre-existing documents. But for now, you're on your own.
Alphabetizing a Single Field
Set up your mongoid document class for alphabetizing on a single field:
class Item
include Mongoid::Document
include Mongoid::Alphadog
field :name, type: String
alphabetize_on :name
end
By default, you will get a free scope that you can use to quickly return your Items in a naturally-alphabetized (A to Z) order:
Item.alphabetized_by(:name)
This is, of course, a Mongoid Criteria object, as you might expect, so you can do all the normal stuff:
Item.where(:color => 'red').alphabetized_by(:name).limit(10)
... will return 10 Items that have a color of 'red' alphabetized by name ascending (A to Z)
If you need your results ordered the other way, for now you'll just have to do it manually with order_by. Alphadog creates the following field on your document:
<OriginalFieldName>_loweralpha
So if you wanted, say, the Items from above to be ordered from Z to A, you would do this:
Item.order_by([[:name_loweralpha, :desc]])
Alphabetizing Multiple Fields
Alphadog can handle multiple fields in a document too!
class User
include Mongoid::Document
include Mongoid::Alphadog
field :first_name, type: String
field :last_name, type: String
field :favorite_color, type: String
alphabetize_on :first_name, :last_name, :favorite_color
end
The alphabetized_by scope can handle multi-field ordering:
User.alphabetized_by(:first_name, :last_name, :favorite_color)
Again, this will do all of the fields in :asc order (A to Z). If you want to do it differently, you'll have to build up your own order_by
User.order_by([[:first_name_loweralpha, :desc], [:last_name_loweralpha, :asc], [:favorite_color_loweralpha, :desc]])
Indexes
Mongoid_Alphadog automatically adds indexes on the XXX_loweralpha fields. Make sure to generate your mongodb indexes by whichever means you prefer.