Checking if a field contains a string

Go To StackoverFlow.com

322

I'm looking for an operator, which allows me to check, if the value of a field contains a certain string.

Something like:

db.users.findOne({$contains:{"username":"son"}})

Is that possible?

2012-05-15 23:20
by johnny


505

You can do it with the following code.

db.users.findOne({"username" : {$regex : ".*son.*"}});
2012-05-16 10:36
by Parvin Gasimzade
Note that this will not make efficient use of an index and result in all values being scanned for matches. See the notes on Regular ExpressionsStennie 2012-07-18 20:54
@Stennie, then what do you suggest to make efficient use of index and find a substring - Blue Sky 2012-11-07 19:31
@Vish: if your common use case is free-text searching of a field and you have a large number of documents, I would tokenize the text for more efficient queries. You could use multikeys for a simple full-text search, or perhaps build an inverted index as a separate collection. For infrequent searches or a small collection of documents, scanning the full index may be acceptable (though not optimal) performance - Stennie 2012-11-08 01:57
Isn't this a bit of an overkill? What you want is

db.users.findOne({"username" : {$regex : "son"}});JamieJag 2014-03-21 12:46

Might want to check out full text search in Mongo 2. - wprl 2014-09-05 18:38
How we can use above in Spring Data Mongo Repository method - PAA 2015-09-22 11:59
Could anyone please reply on above query - NoName 2015-10-11 21:12
in Spring, try Query query = new Query(); query.addCriteria(Criteria.where("username").regex(".son.")) - Rondo 2016-10-24 22:08
@Stennie , Is that statement still true in 3.4? https://docs.mongodb.com/manual/reference/operator/query/regex/#pcre-vs-javascrip - mjwrazor 2017-03-17 15:40
@mjwrazor Still applicable to MongoDB 3.4 as per the $regex documentation page you linked and the information on Index Use. The best case regex search would be case-sensitive prefix scan; searches for non-prefix substrings or with case-insensitive options are not going to result in effective index usage. This is probably fine for small indexes, but extensive use of non-prefix regexes will affect performance for queries against larger indexes - Stennie 2017-03-19 04:51
@mjwrazor The underlying index format is currently B-tree which doesn't lend itself to arbitrary substring matches. A Text index might be a better option if you are doing language-based search (eg. where text can be split on word boundaries and optionally stemmed), but for other use cases (eg. fuzzy matching or free text search) and larger data sets you can potentially work out a more efficient schema or tokenising approach - Stennie 2017-03-19 04:53
@Stennie so if I use the $regex with case-sensitive prefix I will be utilizing the index if i use the regex .*word.*? Also do you happen to know any good documentation for a tokenising approach - mjwrazor 2017-03-20 15:09
@mjwrazor Easiest way to confirm index usage would be to explain your query. I'd also suggest posting a new question with details on your use case rather than discussing in the comments here ;-) - Stennie 2017-03-21 23:10
What is the query? If I want to have case insensitive search for the same example - Rama Krishna 2017-04-04 07:26


148

As Mongo shell support regex, that's completely possible.

db.users.findOne({"username" : /.*son.*/});

If we want the query to be case-insensitive, we can use "i" option, like shown below:

db.users.findOne({"username" : /.*son.*/i});

See: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-RegularExpressions

2012-05-16 00:06
by James Gan
Please include a code snippet demonstrating the usage of regular expressions for searching. Answers should include more information than just a link.. - maerics 2012-05-16 05:13
oh, thanks! Sample code is just added - James Gan 2012-05-16 22:45
The selected answer didn't work for me, but this one did (I'm executing mongo queries via docker exec commands) I think this one should be the selected answer because it appears to be more versatile - Arthur Weborg 2017-05-19 15:13
like the comments in the selected answer I believe db.users.findOne({"username" : /.*son.*/}); could also be overkill and the regex could simple be /son/Arthur Weborg 2017-05-19 15:16
More concise way than using $rege - Lionet Chen 2018-03-06 12:22
Edit this to just use { username: /son/ }Wyck 2018-03-23 19:18


104

https://docs.mongodb.com/manual/reference/sql-comparison/

http://php.net/manual/en/mongo.sqltomongo.php

MySQL

SELECT * FROM users WHERE username LIKE "%Son%"

MongoDB

db.users.find({username:/Son/})
2012-05-16 03:00
by Zheng Kai
Your MongoDB answer is good; consider editing your question to remove the irrelevant MySQL advice - maerics 2012-05-16 05:12
Remove all of query or change it ? most poeple known SQL, it is helpful for understanding MongoD - Zheng Kai 2012-05-16 05:20
@ZhengKai: on this website you should typically answer the question directly, using only the specific technologies tagged and requested - maerics 2012-05-16 23:47
@maerics personally I found Zheng's inclusion of the MySQL very useful as it provided a point of refence - Mike Bartlett 2013-07-11 12:11
I also found the SQL reference relevant, I think it should stay - vikingsteve 2013-11-11 12:35


60

As of version 2.4, you can create a text index on the field(s) to search and use the $text operator for querying.

First, create the index:

db.users.createIndex( { "username": "text" } )

Then, to search:

db.users.find( { $text: { $search: "son" } } )

Benchmarks (~150K documents):

  • Regex (other answers) => 5.6-6.9 seconds
  • Text Search => .164-.201 seconds

Notes:

  • A collection can have only one text index. You can use a wildcard text index if you want to search any string field, like this: db.collection.createIndex( { "$**": "text" } ).
  • A text index can be large. It contains one index entry for each unique post-stemmed word in each indexed field for each document inserted.
  • A text index will take longer to build than a normal index.
  • A text index does not store phrases or information about the proximity of words in the documents. As a result, phrase queries will run much more effectively when the entire collection fits in RAM.
2015-06-24 15:34
by okoboko
no, infact text operator does not allow to execute "contains", so it will only return exact word match, the only option currently as of 3.0 is to use regex , i.e. db.users.find( { username:/son/i } ) this one looksup every user containing "son" (case-insenstive - comeGetSome 2015-09-18 14:56
Do you have to reindex when you add or remove documents to/from the collection - Jake Wilson 2015-10-24 03:39


17

As this is one of the first hits in the search engines, and none of the above seems to work for MongoDB 3.x, here is one regex search that does work:

db.users.find( { 'name' : { '$regex' : yourvalue, '$options' : 'i' } } )

No need to create and extra index or alike.

2016-12-15 06:10
by Nitai


15

Here's what you have to do if you are connecting MongoDB through Python

db.users.find({"username": {'$regex' : '.*' + 'Son' + '.*'}})

you may also use a variable name instead of 'Son' and therefore the string concatenation.

2013-11-15 06:30
by Patthebug
in es2015 you can use backticks { $regex : .*${value}.* - Michael Guild 2016-04-04 02:49


11

Simplest way to accomplish this task

If you want the query to be case-sensitive

db.getCollection("users").find({'username':/Son/})

If you want the query to be case-insensitive

db.getCollection("users").find({'username':/Son/i})
2017-08-29 10:24
by Anurag Misra


0

How to ignore HTML tags in a RegExp match:

var text = '<p>The <b>tiger</b> (<i>Panthera tigris</i>) is the largest <a href="/wiki/Felidae" title="Felidae">cat</a> <a href="/wiki/Species" title="Species">species</a>, most recognizable for its pattern of dark vertical stripes on reddish-orange fur with a lighter underside. The species is classified in the genus <i><a href="/wiki/Panthera" title="Panthera">Panthera</a></i> with the <a href="/wiki/Lion" title="Lion">lion</a>, <a href="/wiki/Leopard" title="Leopard">leopard</a>, <a href="/wiki/Jaguar" title="Jaguar">jaguar</a>, and <a href="/wiki/Snow_leopard" title="Snow leopard">snow leopard</a>. It is an <a href="/wiki/Apex_predator" title="Apex predator">apex predator</a>, primarily preying on <a href="/wiki/Ungulate" title="Ungulate">ungulates</a> such as <a href="/wiki/Deer" title="Deer">deer</a> and <a href="/wiki/Bovid" class="mw-redirect" title="Bovid">bovids</a>.</p>';
var searchString = 'largest cat species';

var rx = '';
searchString.split(' ').forEach(e => {
  rx += '('+e+')((?:\\s*(?:<\/?\\w[^<>]*>)?\\s*)*)';
});

rx = new RegExp(rx, 'igm');

console.log(text.match(rx));

This is probably very easy to turn into a MongoDB aggregation filter.

2018-05-26 03:56
by Tamás Polgár
Ads