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?

Odpowiedzi:


692

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

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

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


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

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.

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.


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.


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

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

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.