Frequently, while working with MongoDB and MongoMapper, I run across an implementation of something that blows me away with its beauty. This, my friends, is one of those times.
Given: a Users collection where the users’ names are stored in an Array key called name. i.e. :name => ["Patterson", "Matt"]. It can be any length, so if they want middle names or titles or whatever, it just gets stuck in there as an element on the array.
Problem: Need to create a really quick lookup to do autocomplete when someone is looking for a particular person in the database.
Solution:
User.all({ :name => /^#{query}.*/i })
end
So when the user types “m” into the autocomplete field, it will quickly populate the suggestions with ["Patterson", "Matt"] and ["Magdalene", "Mary"] and ["Munchausen", "Baron"] and ["Mr.", "John", "Arbuckle"]. But it won’t pickup people with ‘m’ in the middle of any of their name components, like ["Hammer", "Captain"].
How simple is that?
UPDATE: 11 Apr 2010
As it turns out, you can make the above even faster:
User.all({ :name => /^#{query}/i })
end
without the ‘.*’ bit, apparently mongo’s regex implementation gets a huge speed boost since it’s not having to parse the rest of the string once it hits a match.
Be sure to sanitize the regular expression, both for accuracy and security.
http://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS
I’d suggest something like:
User.all({ :name => /^#{Regexp.escape(query)}/i })