ChatGPT解决这个技术问题 Extra ChatGPT

Checking if a field contains a string

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?


S
Skippy le Grand Gourou

You can do it with the following code.

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

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 Expressions
@Stennie, then what do you suggest to make efficient use of index and find a substring.
@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.
Isn't this a bit of an overkill? What you want is db.users.findOne({"username" : {$regex : "son"}});
Might want to check out full text search in Mongo 2.6
J
James Gan

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


Please include a code snippet demonstrating the usage of regular expressions for searching. Answers should include more information than just a link...
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.
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/
More concise way than using $regex
Edit this to just use { username: /son/ }
Z
Zheng Kai

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

Remove all of query or change it ? most poeple known SQL, it is helpful for understanding MongoDB
@maerics personally I found Zheng's inclusion of the MySQL very useful as it provided a point of refence.
I also found the SQL reference relevant, I think it should stay.
Indeed. The SQL example is just two lines of text. Some people may prefer to ignore it, while others may benefit from it, and the cost to those in the first group is probably far outweighed by the benefit to those in the second group.
@zhengKai What if you want to query username like son, and other value. Is it possible to have multiple conditions? ex: db.users.find({username:/Son/,/Dad/,/Mom/}) to retrieve all usernames that has "Son, dad, mom" etc..
o
okoboko

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.


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)
Do you have to reindex when you add or remove documents to/from the collection?
The title of the question says "contains". full text search is not applicable to the question.
@comeGetSome You're right. any updates on how to do this in a fast and effective manner?
N
Nitai

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.


Regexes need to be sanitized.
came from google and this is the only one that works for me. From the docs, the option i is for "Case insensitivity to match upper and lower cases."
2022, it is correct answer. Because if I use $regaxe instead '$regex' Pylance give me error.
Hey @Nitai just want question I wan to give for 2 values in regex. I mean either the string matches with value1 or value2 . How can I modify this query?
@Nitai above thing is not working with url search google.com/test/test_page
P
Patthebug

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.


above query was not working with url in aggregate under $match operator, like, "details.uri": { "$regex": ".*phubprod.princeton.edu/psp/phubprod.*", "$options": "i" }
A
Anurag Misra

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

how to use variable with regex??
H
Hisham

ideal answer its use index i option for case-insensitive

db.users.findOne({"username" : new RegExp(search_value, 'i') });

Regexes need to be sanitized.
t
turivishal

This should do the work

db.users.find({ username: { $in: [ /son/i ] } });

The i is just there to prevent restrictions of matching single cases of letters.

You can check the $regex documentation on MongoDB documentation. Here's a link: https://docs.mongodb.com/manual/reference/operator/query/regex/


T
Thanh Nhật Nguyễn

I use this code and it work for search substring

db.users.find({key: { $regex: new RegExp(value, 'i')}})

b
bello hargbola

If you need to do the search for more than one attribute you can use the $or. For example

Symbol.find(
  {
    $or: [
      { 'symbol': { '$regex': input, '$options': 'i' } },
      { 'name': { '$regex': input, '$options': 'i' } }
    ]
  }
).then((data) => {
  console.log(data)
}).catch((err) => {
  console.log(err)
})

Here you are basing your search on if the input is contained in the symbol attribute or the name attribute.


K
KushalSeth

If the regex is not working in your Aggregate solution and you have nested object. Try this aggregation pipeline: (If your object structure is simple then, just remove the other conditions from below query):

db.user.aggregate({$match: 
     {$and:[
   {"UserObject.Personal.Status":"ACTV"},
   {"UserObject.Personal.Address.Home.Type":"HME"},
   {"UserObject.Personal.Address.Home.Value": /.*son.*/ }
   ]}}
   ) 

One other way would be to directly query like this:

db.user.findOne({"UserObject.Personal.Address.Home.Value": /.*son.*/ });

S
Scott Wager

If your regex includes a variable, make sure to escape it.

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}

This can be used like this

new RegExp(escapeRegExp(searchString), 'i')

Or in a mongoDb query like this

{ '$regex': escapeRegExp(searchString) }

Posted same comment here


F
F.H.

For aggregation framework

Field search

('$options': 'i' for case insensitive search)

db.users.aggregate([
    {
        $match: {
            'email': { '$regex': '@gmail.com', '$options': 'i' }
        }
    }
]);

Full document search

(only works on fields indexed with a text index

db.articles.aggregate([
    {
        $match: { $text: { $search: 'brave new world' } }
    }
])

how can i use first option with URL search, like i want to exclude http protocol and query parameters, google.com?id=1 in this can http,www and query params would be ignored
You can pass in any valid regex pattern, see mongodb.com/docs/manual/reference/operator/query/regex
T
Tamás Polgár

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.