Sprawdzanie, czy pole zawiera ciąg

453

Szukam operatora, który pozwala mi sprawdzić, czy wartość pola zawiera określony ciąg znaków.

Coś jak:

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

Czy to jest możliwe?

Jasio
źródło

Odpowiedzi:

692

Możesz to zrobić za pomocą następującego kodu.

db.users.findOne({"username" : {$regex : ".*son.*"}});
Parvin Gasimzade
źródło
16
Zauważ, że nie spowoduje to efektywnego wykorzystania indeksu i spowoduje skanowanie wszystkich wartości w poszukiwaniu dopasowań. Zobacz uwagi na temat wyrażeń regularnych
Stennie,
7
@Stennie, to co sugerujesz, aby efektywnie wykorzystać indeks i znaleźć podłańcuch.
Blue Sky
4
@ Vish: jeśli twoim powszechnym przypadkiem użycia jest wyszukiwanie w polu dowolnego tekstu i masz dużą liczbę dokumentów, tokenizuję tekst, aby uzyskać bardziej wydajne zapytania. Możesz użyć multikeys do prostego wyszukiwania pełnotekstowego lub zbudować odwrócony indeks jako osobną kolekcję. W przypadku rzadkich wyszukiwań lub niewielkiej kolekcji dokumentów skanowanie pełnego indeksu może być akceptowalną (choć nie optymalną) wydajnością.
Stennie,
98
Czy to nie jest przesada? To, czego chcesz, to db.users.findOne({"username" : {$regex : "son"}});
JamieJag
3
Może chcesz sprawdzić wyszukiwanie pełnotekstowe w Mongo 2.6
wprl
179

Ponieważ regex obsługuje powłokę Mongo, jest to całkowicie możliwe.

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

Jeśli chcemy, aby zapytanie nie rozróżniało wielkości liter, możemy użyć opcji „i”, jak pokazano poniżej:

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

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

James Gan
źródło
1
Dołącz fragment kodu demonstrujący użycie wyrażeń regularnych do wyszukiwania. Odpowiedzi powinny zawierać więcej informacji niż link ...
maerics
1
Wybrana odpowiedź nie działała dla mnie, ale ta zadziałała (wykonuję zapytania mongo za pomocą poleceń docker exec). Myślę, że ta odpowiedź powinna być wybrana, ponieważ wydaje się bardziej uniwersalna.
Arthur Weborg
5
podobnie jak komentarze w wybranej odpowiedzi, uważam, że db.users.findOne({"username" : /.*son.*/});może to być również przesada, a wyrażenie regularne może być po prostu/son/
Arthur Weborg
2
Bardziej zwięzły sposób niż użycie wyrażenia regularnego
Lionet Chen
4
Edytuj to, aby po prostu użyć{ 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/})
Zheng Kai
źródło
8
Twoja odpowiedź MongoDB jest dobra; rozważ edycję pytania, aby usunąć niepotrzebne porady MySQL.
maerics
31
Usunąć wszystkie zapytania lub zmienić? najbardziej znany SQL, pomaga zrozumieć MongoDB
Zheng Kai
4
@ZhengKai: na tej stronie zazwyczaj należy bezpośrednio odpowiedzieć na pytanie, używając tylko określonych technologii oznaczonych i wymaganych.
maerics
98
@ maerics osobiście uznałem włączenie MySQL przez Zhenga za bardzo przydatne, ponieważ stanowiło punkt odniesienia.
Mike Bartlett
50
Uważam również, że odwołanie SQL ma znaczenie, myślę, że powinno zostać.
vikingsteve
69

Począwszy od wersji 2.4, możesz utworzyć indeks tekstowy na polach, aby wyszukać i użyć operatora $ text do zapytania.

Najpierw utwórz indeks:

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

Następnie, aby wyszukać:

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

Punkty odniesienia (~ 150 000 dokumentów):

  • Regex (inne odpowiedzi) => 5,6-6,9 sekundy
  • Wyszukiwanie tekstu => .164-.201 sekund

Uwagi:

  • Kolekcja może mieć tylko jeden indeks tekstowy. Można używać symboli wieloznacznych indeksu tekstowego, jeśli chcesz wyszukać dowolny pole ciąg, tak: db.collection.createIndex( { "$**": "text" } ).
  • Indeks tekstowy może być duży. Zawiera jeden wpis indeksu dla każdego unikalnego słowa post-stemed w każdym indeksowanym polu dla każdego wstawionego dokumentu.
  • Indeks tekstowy będzie trwał dłużej niż zwykły indeks.
  • Indeks tekstowy nie przechowuje zwrotów ani informacji o bliskości słów w dokumentach. W rezultacie zapytania do wyrażeń będą działać znacznie efektywniej, gdy cała kolekcja zmieści się w pamięci RAM.
okoboko
źródło
14
nie, operator tekstu infact nie pozwala na wykonanie „zawiera”, więc zwróci tylko dokładne dopasowanie słowa, jedyną opcją obecnie od 3.0 jest użycie wyrażenia regularnego, tj. db.users.find ({nazwa użytkownika: / son / i} ) ten wyszukuje każdego użytkownika zawierającego „syn” (case-insenstive)
comeGetSome 18.09.2015
3
Czy musisz ponownie indeksować, gdy dodajesz lub usuwasz dokumenty do / z kolekcji?
Jake Wilson
Tytuł pytania brzmi „zawiera”. wyszukiwanie pełnotekstowe nie dotyczy pytania.
Donato
29

Ponieważ jest to jedno z pierwszych trafień w wyszukiwarkach i żadne z powyższych nie wydaje się działać w MongoDB 3.x, oto jedno wyszukiwanie wyrażeń regularnych, które działa:

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

Nie ma potrzeby tworzenia i dodatkowego indeksowania ani podobnych.

Nitai
źródło
1
Regeksy muszą zostać zdezynfekowane.
sean
16

Oto, co musisz zrobić, jeśli łączysz MongoDB przez Python

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

możesz także użyć nazwy zmiennej zamiast „Son”, a zatem konkatenacji łańcucha.

Patthebug
źródło
w es2015 możesz użyć backticks {$ regex: .*${value}.*}
Michael Guild
16

Najprostszy sposób na wykonanie tego zadania

Jeśli chcesz, aby w zapytaniu rozróżniana była wielkość liter

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

Jeśli chcesz, aby zapytanie nie rozróżniało wielkości liter

db.getCollection("users").find({'username':/Son/i})
Anurag Misra
źródło
1
jak używać zmiennej z wyrażeniem regularnym ??
Hisham,
4

idealna odpowiedź jego indeks wykorzystania i opcja dla bez rozróżniania wielkości liter

db.users.findOne({"username" : new RegExp(search_value, 'i') });
Hisham
źródło
Regeksy muszą zostać zdezynfekowane.
sean
1

Jak zignorować tagi HTML w dopasowaniu 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));

Prawdopodobnie bardzo łatwo można go przekształcić w filtr agregacji MongoDB.

Tamás Polgár
źródło