TomG
TomG

Reputation: 2529

MongoDB - find if a field value is contained in a given string

Is it possible to query documents where a specific field is contained in a given string?

for example if I have these documents:

{a: 'test blabla'},
{a: 'test not'}

I would like to find all documents that field a is fully included in the string "test blabla test", so only the first document would be returned.

I know I can do it with aggregation using $indexOfCP and it is also possible with $where and mapReduce. I was wandering if it's possible to do it in find query using the standard MongoDB operators (e.g., $gt, $in).

thanks.

Upvotes: 3

Views: 2493

Answers (3)

May Rest in Peace
May Rest in Peace

Reputation: 2207

If you are using Mongo v3.6+, you can use $expr.

As you mentioned $indexOfCP can be used to get index, here it will be

{ 
   "$expr": {
       {$ne : [{$indexOfCP: ["test blabla test", "$a"]}, -1]}
   }
} 

The field name should be prefixed with a dollar sign ($), as $expr allows filters from aggregation pipeline.

Upvotes: 0

Ciabaros
Ciabaros

Reputation: 2159

I can think of 2 ways you could do this:

Option 1

Using $where:

db.someCol.find( { $where: function() { return "test blabla test".indexOf(this.a) > -1; } }

Explained: Find all documents whose value of field "a" is found WITHIN some given string.

This approach is universal, as you can run any code you like, but less recommended from a performance perspective. For instance, it cannot take advantage of indexes. Read full $where considerations here: https://docs.mongodb.com/manual/reference/operator/query/where/#considerations

Option 2

Using regex matching trickery, ONLY under certain circumstances; below is an example that only works with matching that the field value is found as a starting substring of the given string:

db.someCol.find( { a : /^(t(e(s(t( (b(l(a(b(l(a( (t(e(s(t)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?$/ } )

Explained: Break up the components of your "should-be-contained-within" string and match against all sub-possibilities of that with regex.

For your case, this option is pretty much insane, but it's worth noting as there may be specific cases (such as limited namespace matching), where you would not have to break up each letter, but some very finite set of predetermined parts. And in that case, this option could still make use of indexes, and not suffer the $where performance pentalties (as long as the complexity of the regex doesn't outweigh that benefit :)

Upvotes: 1

sitakant
sitakant

Reputation: 1878

You can use regex to search .

db.company.findOne({"companyname" : {$regex : ".*hello.*"}});

Upvotes: 0

Related Questions