2015-10-13 15 views

Odpowiedz

5

Począwszy od wersji MongoDB 3.4 możemy nam e operator $indexOfArray, aby zwrócić indeks, w którym dany element można znaleźć w tablicy.

$indexOfArray ma trzy argumenty. Pierwsza to nazwa pola tablicy poprzedzonego znakiem $.

Drugi element to element, a trzeci opcjonalny to indeks do rozpoczęcia wyszukiwania. $indexOfArray zwraca pierwszy indeks, w którym element zostanie znaleziony, jeśli nie podano indeksu, aby rozpocząć wyszukiwanie.


Demo:

> db.collection.insertOne({ "_id" : 123, "food": [ "apple", "mango", "banana", "mango" ] }) 
{ "acknowledged" : true, "insertedId" : 123 } 
> db.collection.aggregate([ { "$project": { "matchedIndex": { "$indexOfArray": [ "$food", "mango" ] } } } ]) 
{ "_id" : 123, "matchedIndex" : 1 } 
> db.collection.aggregate([ { "$project": { "matchedIndex": { "$indexOfArray": [ "$food", "mango", 2 ] } } } ]) 
{ "_id" : 123, "matchedIndex" : 3 } 
> db.collection.aggregate([ { "$project": { "matchedIndex": { "$indexOfArray": [ "$food", "apricot" ] } } } ] ) 
{ "_id" : 123, "matchedIndex" : -1 } 
+0

Ta odpowiedź jest najlepsza dla wersji 3.4+, ale jeśli używasz starej wersji, powinna nastąpić odpowiedź @BlakesSeven –

4

Naprawdę nie ma innego sposobu („po stronie serwera”) niż przy użyciu mapReduce:

db.collection.mapReduce(
    function() { 
     emit(this._id, this.food.indexOf("mango")); 
    }, 
    function() {}, // reducer never gets called since all _id is unique 
    { 
     "out": { "inline": 1 }, 
     "query": { "food": "mango" } 
    } 
) 

Jest to jedyna rzecz, która zwróci coś innego w zmodyfikowanej formie innej niż w samym dokumencie , a także przy użyciu wymaganej oceny JavaScript w celu ustalenia odpowiedzi, niestety nie ma "natywnego" operatora, który to zrobi.

Jeśli nie jest to potrzebne do rzeczywistych celów agregacji, lepiej jest po prostu zrobić podobne "dopasowanie indeksu tablicowego" w natywnym kodzie klienta podczas pracy "na podstawie dokumentu".

+0

pracował jak urok! Ale co z wydajnością na dużej kolekcji przy wywołaniu mapReduce? –

+0

@JamesYang Myślę, że musisz zrozumieć, że uważam, że nie powinieneś tego robić tak czy inaczej, chyba że faktycznie musisz zebrać wynik dalej (jak już wspomniano). Nie ma alternatywy po stronie serwera (również już wspomniano), więc albo utknąłeś z mapReduce w przypadku "po stronie serwera", albo przetwarzasz indeks tablicy na dokument w kliencie (jak już zalecono). –

+0

Z opcjami '{jsMode: true}' jest to dobre dla wydajności? w twoim doświadczeniu –

0

W powłoce Mongo (w Robomongo również) Chciałbym wykonaj następujące czynności:

var food = db.getCollection('yourCollection').findOne({_id: '123'}).food; 
    print('Index of mango: ' + food.indexOf('mango')); 

lub zapisać ten kod w any_file.js a następnie uruchomić z linii poleceń:

mongo your_db any_file.js 

To będzie produkować coś takiego:

MongoDB shell version: 2.4.9 
    connecting to: localhost:27017/your_db 
    Index of mango: 2 
+0

rozwiązanie, ale może nie jest to praktyka –