Verifica se un campo contiene una stringa


454

Sto cercando un operatore, che mi consente di verificare se il valore di un campo contiene una determinata stringa.

Qualcosa di simile a:

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

È possibile?

Risposte:


693

Puoi farlo con il seguente codice.

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

16
Si noti che ciò non farà un uso efficiente di un indice e comporterà la scansione di tutti i valori alla ricerca di corrispondenze. Vedi le note su Regular Expressions
Stennie,

7
@Stennie, allora cosa suggerisci per fare un uso efficiente dell'indice e trovare una sottostringa.
Blue Sky,

4
@Vish: se il tuo caso d'uso comune è la ricerca a testo libero di un campo e hai un gran numero di documenti, toccherei il testo per domande più efficienti. È possibile utilizzare i tasti multipli per una semplice ricerca full-text o forse creare un indice invertito come raccolta separata. Per ricerche poco frequenti o una piccola raccolta di documenti, la scansione dell'indice completo può essere accettabile (anche se non ottimale).
Stennie,

98
Non è un po 'eccessivo? Quello che vuoi è db.users.findOne({"username" : {$regex : "son"}});
JamieJag il

3
Potrebbe voler controllare la ricerca a testo integrale in Mongo 2.6
wprl

179

Poiché la shell Mongo supporta regex, questo è completamente possibile.

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

Se vogliamo che la query non faccia distinzione tra maiuscole e minuscole, possiamo usare l'opzione "i", come mostrato di seguito:

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

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


1
Includi uno snippet di codice che dimostri l'utilizzo di espressioni regolari per la ricerca. Le risposte dovrebbero includere più informazioni di un semplice link ...
Maerics,

1
La risposta selezionata non ha funzionato per me, ma questa ha funzionato (sto eseguendo query mongo tramite i comandi docker exec) Penso che questa dovrebbe essere la risposta selezionata perché sembra essere più versatile.
Arthur Weborg,

5
come i commenti nella risposta selezionata, credo che db.users.findOne({"username" : /.*son.*/});potrebbe anche essere eccessivo e il regex potrebbe essere semplice/son/
Arthur Weborg,

2
Modo più conciso rispetto all'utilizzo di $ regex
Lionet Chen

4
Modifica questo per usare solo{ username: /son/ }
Wyck

150

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

8
La tua risposta MongoDB è buona; considera di modificare la tua domanda per rimuovere i consigli irrilevanti su MySQL.
Maerici,

31
Rimuovere tutta la query o cambiarla? la maggior parte delle persone conosciute SQL, è utile per capire MongoDB
Zheng Kai

4
@ZhengKai: su questo sito Web in genere è necessario rispondere direttamente alla domanda, utilizzando solo le tecnologie specifiche contrassegnate e richieste.
Maerics,

98
@maerics personalmente ho trovato molto utile l'inclusione di MySQL da parte di Zheng in quanto ha fornito un punto di riferimento.
Mike Bartlett,

50
Ho anche trovato pertinente il riferimento SQL, penso che dovrebbe rimanere.
Vienna

69

A partire dalla versione 2.4, è possibile creare un indice di testo nei campi per cercare e utilizzare l' operatore $ text per le query.

Innanzitutto, crea l'indice:

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

Quindi, per cercare:

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

Benchmark (~ 150.000 documenti):

  • Regex (altre risposte) => 5,6-6,9 secondi
  • Ricerca testo => .164-.201 secondi

Appunti:

  • Una raccolta può avere solo un indice di testo. È possibile utilizzare un indice di testo jolly se si desidera cercare qualsiasi campo di stringa, in questo modo: db.collection.createIndex( { "$**": "text" } ).
  • Un indice di testo può essere grande. Contiene una voce di indice per ogni parola post-derivata univoca in ciascun campo indicizzato per ciascun documento inserito.
  • La compilazione di un indice di testo richiederà più tempo di un indice normale.
  • Un indice di testo non memorizza frasi o informazioni sulla vicinanza delle parole nei documenti. Di conseguenza, le query a frase verranno eseguite in modo molto più efficace quando l'intera raccolta si adatta alla RAM.

14
no, infatti l'operatore di testo non consente di eseguire "contiene", quindi restituirà solo la corrispondenza esatta delle parole, l'unica opzione attualmente al 3.0 è quella di utilizzare regex, ovvero db.users.find ({username: / son / i} ) questo cerca tutti gli utenti che contengono "figlio" (senza distinzione tra maiuscole e minuscole)
comeGetSome

3
Devi reindicizzare quando aggiungi o rimuovi documenti da / verso la collezione?
Jake Wilson,

Il titolo della domanda dice "contiene". la ricerca full-text non è applicabile alla domanda.
Donato,

29

Poiché questo è uno dei primi successi nei motori di ricerca e nessuna delle precedenti sembra funzionare con MongoDB 3.x, ecco una ricerca regex che funziona:

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

Non è necessario creare un indice aggiuntivo o simile.


1
I regex devono essere disinfettati.
sean,

16

Ecco cosa devi fare se stai collegando MongoDB tramite Python

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

puoi anche usare un nome di variabile invece di 'Son' e quindi la concatenazione di stringhe.


in es2015 puoi usare i backtick {$ regex: .*${value}.*}
Michael Guild

16

Il modo più semplice per svolgere questo compito

Se si desidera che la query faccia distinzione tra maiuscole e minuscole

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

Se si desidera che la query non faccia distinzione tra maiuscole e minuscole

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

1
come usare la variabile con regex ??
Hisham,

4

risposta ideale all'indice di utilizzo i opzione per maiuscole e minuscole

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

I regex devono essere disinfettati.
sean,


1

Come ignorare i tag HTML in una corrispondenza RegExp:

var text = '<p>The <b>tiger</b> (<i>Panthera tigris</i>) is the largest <a href="https://stackoverflow.com/wiki/Felidae" title="Felidae">cat</a> <a href="https://stackoverflow.com/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="https://stackoverflow.com/wiki/Panthera" title="Panthera">Panthera</a></i> with the <a href="https://stackoverflow.com/wiki/Lion" title="Lion">lion</a>, <a href="https://stackoverflow.com/wiki/Leopard" title="Leopard">leopard</a>, <a href="https://stackoverflow.com/wiki/Jaguar" title="Jaguar">jaguar</a>, and <a href="https://stackoverflow.com/wiki/Snow_leopard" title="Snow leopard">snow leopard</a>. It is an <a href="https://stackoverflow.com/wiki/Apex_predator" title="Apex predator">apex predator</a>, primarily preying on <a href="https://stackoverflow.com/wiki/Ungulate" title="Ungulate">ungulates</a> such as <a href="https://stackoverflow.com/wiki/Deer" title="Deer">deer</a> and <a href="https://stackoverflow.com/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));

Questo è probabilmente molto facile da trasformare in un filtro di aggregazione MongoDB.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.