Say I have a collection of users and want to implement autocomplete on the usernames of those users. I looked at the mongodb docs and $regex seems to be one way to do this. Is there a better way? By better I mean more performant/better practice.
3 Answers
As suggested by @Thilo, you can use several ideas including prefixing.
The most important thing is to have very quick request (because you want autocomplete to feel instaneous). So you have to use query which will use properly indexes.
With regexp : use /^prefix/
(the important thing is the ^ to specify the beginning of line which is mandatory to make the query use index).
The range query is good too : { $gt : 'jhc', $lt: 'jhd' } }
More complicated but faster : you can store prefix-trees in mongo (aka tries) with entries like :
{usrPrefix : "anna", compl : ["annaconda", "annabelle", "annather"]}
{usrPrefix : "ann", compl : ["anne", "annaconda", "annabelle", "annather"]}
This last solution is very fast (if indexes on compl of course) but not space efficient at all. You know the trade-off you have too choose.

- 2,479
- 1
- 26
- 45
-
Excellent answer. Hadn't though of completion with tries. Personally I've never had an 'instantaneous' feeling with using Regexes in Mongo. This should do the trick to make it much faster! – Vivek Aug 24 '12 at 22:56
-
Indeed, regexp in mongo are not really well implemented. However, when you want something fluid you do not think to query database in live, latency is simply too high. A proper way to implement auto-completion would be to load asynchronously some usual completions and complete as time (and user input) goes on. – kamaradclimber Aug 25 '12 at 08:39
-
I tried both `Regex` and `range query`, and I got a better result with `Regex` and index – Mohammad Taherian Oct 07 '22 at 20:09
We do it using regex and it's fast as long as you have an index and you use /^value/
Be aware you can't use the case insensitive option with an index, so you may want to store a lower case version of your string as another field in your document and use that for the autocomplete.
I've done tests with 3 million+ documents and it still appears instantaneous.

- 386
- 1
- 6
-
I tried with `IgnoreCase` on .net driver and it seems it works fine. – Mohammad Taherian Oct 07 '22 at 20:11
If you are looking for prefixes, you could use a range query (not sure about the exact syntax):
db.users.find({'username': { $gt : 'jhc', $lt: 'jhd' } } )
And you want an index on the username field.

- 257,207
- 101
- 511
- 656
-
Could you explain how the range query works in this example? for example if I have "cats" in my collection how would "ca" return the correct term. – wazzaday Feb 10 '15 at 11:47
-