2017-02-26 20 views
13

Powiedzmy mam kolekcję Mongo z text index na polu itemName z tych 3 dokumentów:

{ 
    _id: ..., 
    itemName: 'Mashed carrots with big carrot pieces', 
    price: 1.29 
}, 
{ 
    _id: ..., 
    itemName: 'Carrot juice', 
    price: 0.79 
}, 
{ 
    _id: ..., 
    itemName: 'Apple juice', 
    price: 1.49 
} 

Potem Exec zapytanie jak tak :

db.items.find({ $text: { $search: 'Car' } }, { score: { $meta: "textScore" } }).sort({ score: { $meta: "textScore" } }); 

Jak wymusić Mongo do dokumentów zwrotnych rozpoczynających się od „car” (wielkość liter ma znaczenie) przed powrocie wszelkie inne dokumenty zawierające również „car” trochę gdzie w ciągu znaków itemName?

Więc chcę odzyskać dokumenty w następującej kolejności:

[ 
    {..., itemName: 'Carrot Juice', ...}, 
    {..., itemName: 'Mashed carrots with big carrot pieces', ...} 
] 

Oczywiście ten ma być wykorzystywany w funkcji wyszukiwania, co oznacza, że ​​całkowity sens, aby pokazać użytkownikowi elementy wychodząc z jego ciąg wyszukiwania przed wyświetleniem innych elementów po tym.

Do tej pory używałem standardowego wyrażenia regularnego, ale tutaj występ oczywiście jest znacznie gorszy! + ponieważ muszę przeszukiwać wielkość liter, zgodnie z dokumentami, normalne regex nie używa żadnych indeksów w ogóle ?!

EDIT:

Również czasami zachowanie $text jest bardzo dziwne. Na przykład mam około 10-15 pozycji, gdzie itemName zaczyna się od słowa "Zwiebel". To zapytanie

db.items.find({ $text: { $search: "Zwiebel" }, supplier_id: 'iNTJHEf5YgBPicTrJ' }, { score: { $meta: "textScore" } }).sort({ score: { $meta: "textScore" } }); 

działa jak czar i zwraca wszystkie te dokumenty, gdy tego zapytania

db.items.find({ $text: { $search: "Zwie" }, supplier_id: 'iNTJHEf5YgBPicTrJ' }, { score: { $meta: "textScore" } }).sort({ score: { $meta: "textScore" } }); 

niczego nie wrócić! Tylko zmieniając "Zwiebel" na "Zwie" w $search.

Naprawdę nie rozumiem, jak to jest możliwe ?!

najlepiej P

+0

Jaki ma to wpływ na sortowanie według textScore? –

+0

proszę sprawdź moją edycję! :-) Dziękuję Ci! –

+0

@PatrickDaVader zobacz moją edycję – felix

Odpowiedz

7

Rozwiązaniem jest użycie operatora $indexOfCP introcuced w MongoDB 3.4

Ten operator zwraca indeks wystąpienia napisu w innym String, a -1, jeśli nie ma Występowanie

jak to działa:

  1. odfiltrować wszystkie dokumenty nie zawierające „samochód” z regex: /car/gi (przypadek inensitive)
  2. utworzyć pole o nazwie index który przechowuje indeks „samochód” w itemName
  3. sortowania dokumentów na 0.123.pole

zapytanie będzie wyglądać następująco:

db.items.aggregate([ 
    { 
     $match:{ 
     itemName:/car/gi 
     } 
    }, 
    { 
     $project:{ 
     index:{ 
      $indexOfCP:[ 
       { 
        $toLower:"$itemName" 
       }, 
       "car" 
      ] 
     }, 
     price:1, 
     itemName:1 
     } 
    }, 
    { 
     $sort:{ 
     index:1 
     } 
    } 
]) 

i to zwraca:

{ "_id" : 2, "itemName" : "Carrot juice", "price" : 0.79, "index" : 0 } 
{ "_id" : 1, "itemName" : "Mashed carrots with big carrot pieces", "price" : 1.29, "index" : 7 } 

Edit:

Dla zachowania indeksu $text, to jest całkowicie normalny

Indeks tekstowy tokenizuje tekst za pomocą ograniczników (domyślnymi ogranicznikami są białe znaki i znaki interpunkcyjne). To może być używany tylko do wyszukiwania całych światów, a więc nie będzie pracować dla podczęści słów

z mongodb text index documentation

$ text będzie tokenize ciąg wyszukiwania używając spacje i znaki interpunkcyjne najwięcej jako ograniczniki, i wykonaj logiczne OR wszystkich takich tokenów w ciągu wyszukiwania.

+0

dziękuję za odpowiedź! Sprawdź także moją edycję w OP! Dzięki! –