Mongo Beauty #1

Posted: 2nd February 2010 by M. E. Patterson in Coding
Tags: , ,

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:

  def self.named(query)
    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:

  def self.named(query)
    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.

  1. andrew says:

    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 })