Verificando se um campo contém uma sequência

454

Estou procurando um operador, que me permita verificar se o valor de um campo contém uma determinada string.

Algo como:

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

Isso é possível?

johnny
fonte

Respostas:

693

Você pode fazer isso com o seguinte código.

db.users.findOne({"username" : {$regex : ".*son.*"}});
Parvin Gasimzade
fonte
16
Observe que isso não fará uso eficiente de um índice e resultará na verificação de todos os valores em busca de correspondências. Veja as notas em Expressões regulares
Stennie
7
@ Stennie, o que você sugere para fazer um uso eficiente do índice e encontrar uma substring.
Blue Sky
4
@ Vish: se o seu caso de uso comum for a pesquisa de texto livre em um campo e você tiver um grande número de documentos, eu tokenizaria o texto para consultas mais eficientes. Você pode usar multikeys para uma pesquisa simples em texto completo ou talvez criar um índice invertido como uma coleção separada. Para pesquisas pouco frequentes ou uma pequena coleção de documentos, a digitalização do índice completo pode ser um desempenho aceitável (embora não ideal).
Stennie
98
Isso não é um exagero? O que você quer é db.users.findOne({"username" : {$regex : "son"}});
JamieJag
3
Pode querer verificar a pesquisa de texto completo no Mongo 2.6
wprl 5/09/14
179

Como o shell Mongo suporta regex, isso é completamente possível.

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

Se quisermos que a consulta não diferencie maiúsculas de minúsculas, podemos usar a opção "i", como mostrado abaixo:

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

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

James Gan
fonte
1
Inclua um trecho de código que demonstre o uso de expressões regulares para pesquisa. As respostas devem incluir mais informações do que apenas um link ...
maerics
1
A resposta selecionada não funcionou para mim, mas esta funcionou (estou executando consultas mongo por meio dos comandos docker exec). Acho que essa deve ser a resposta selecionada, pois parece ser mais versátil.
Arthur Weborg
5
como os comentários na resposta selecionada Acredito db.users.findOne({"username" : /.*son.*/});também poderia ser um exagero e o regex poderia simples ser/son/
Arthur Weborg
2
Mais forma concisa do que usando $ regex
Lionet Chen
4
Edite isso para usar apenas #{ username: /son/ }
Wyck 23/03
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/})
Zheng Kai
fonte
8
Sua resposta do MongoDB é boa; considere editar sua pergunta para remover os conselhos irrelevantes do MySQL.
maerics 16/05
31
Remover todas as consultas ou alterá-las? mais poeple conhecido SQL, é útil para a compreensão MongoDB
Zheng Kai
4
@ZhengKai: neste site, você normalmente deve responder diretamente à pergunta, usando apenas as tecnologias específicas marcadas e solicitadas.
maerics
98
@maerics pessoalmente, achei a inclusão de Zheng no MySQL muito útil, pois fornecia um ponto de referência.
9133 Mike Bartlett
50
Eu também achei a referência SQL relevante, acho que deveria ficar.
vikingsteve
69

A partir da versão 2.4, você pode criar um índice de texto nos campos para pesquisar e usar o operador $ text para consulta.

Primeiro, crie o índice:

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

Em seguida, para pesquisar:

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

Benchmarks (~ 150K documentos):

  • Regex (outras respostas) => 5,6-6,9 segundos
  • Pesquisa de texto => .164-.201 segundos

Notas:

  • Uma coleção pode ter apenas um índice de texto. Você pode usar um índice de texto curinga se você deseja pesquisar qualquer campo corda, como esta: db.collection.createIndex( { "$**": "text" } ).
  • Um índice de texto pode ser grande. Ele contém uma entrada de índice para cada palavra pós-derivada exclusiva em cada campo indexado para cada documento inserido.
  • Um índice de texto levará mais tempo para criar do que um índice normal.
  • Um índice de texto não armazena frases ou informações sobre a proximidade de palavras nos documentos. Como resultado, as consultas por frase serão executadas com muito mais eficiência quando a coleção inteira couber na RAM.
okoboko
fonte
14
não, o operador de texto de fato não permite executar "contains"; portanto, ele retornará apenas a correspondência exata de palavras; a única opção atualmente a partir do 3.0 é usar o regex, ou seja, db.users.find ({nome de usuário: / son / i} ) esta uma looksup cada utilizador contendo "filho" (caso-insenstive)
comeGetSome
3
Você precisa reindexar ao adicionar ou remover documentos de / para a coleção?
Jake Wilson
O título da pergunta diz "contém". a pesquisa de texto completo não é aplicável à pergunta.
Donato
29

Como esse é um dos primeiros hits nos mecanismos de pesquisa, e nenhuma das opções acima parece funcionar no MongoDB 3.x, aqui está uma pesquisa de regex que funciona:

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

Não há necessidade de criar um índice extra ou similar.

Nitai
fonte
1
Regexes precisam ser higienizados.
sean
16

Aqui está o que você deve fazer se estiver conectando o MongoDB através do Python

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

você também pode usar um nome de variável em vez de 'Son' e, portanto, a concatenação de strings.

Patthebug
fonte
no es2015 você pode usar os backticks {$ regex: .*${value}.*} #
Michael Guild
16

Maneira mais simples de realizar esta tarefa

Se você deseja que a consulta faça distinção entre maiúsculas e minúsculas

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

Se você deseja que a consulta não diferencie maiúsculas de minúsculas

db.getCollection("users").find({'username':/Son/i})
Anurag Misra
fonte
1
como usar variável com regex ??
Hisham
4

resposta ideal sua opção de índice de uso i para não fazer distinção entre maiúsculas e minúsculas

db.users.findOne({"username" : new RegExp(search_value, 'i') });
Hisham
fonte
Regexes precisam ser higienizados.
sean
2

Isso deve fazer o trabalho

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

O iestá ali apenas para evitar restrições de correspondência casos isolados de cartas.

Você pode verificar a documentação $ regex na documentação do MongoDB. Aqui está um link: https://docs.mongodb.com/manual/reference/operator/query/regex/

tate
fonte
1

Como ignorar tags HTML em uma correspondência 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));

Provavelmente é muito fácil se transformar em um filtro de agregação do MongoDB.

Tamás Polgár
fonte