2015-10-13 7 views
6

Denken Sie an diesem MongoDB Dokument:Get-Index von bestimmtem Elemente in Array-Feld in MongoDB

{_id:123, "food":[ "apple", "banana", "mango" ]} 

Frage: Wie wird die Position von mango in Essen zu bekommen?

Die Abfrage sollte oben 2 zurückgeben, und das gesamte Dokument nicht zurückgeben.

Bitte zeigen Sie freundlich die Arbeitsabfrage.

Antwort

5

Ab MongoDB Version 3.4 können wir uns Der Operator gibt den Index zurück, an dem ein bestimmtes Element im Array gefunden werden kann.

$indexOfArray braucht drei Argumente. Der erste ist der Name des Felds Array mit dem Präfix $ Vorzeichen.

Die zweite ist das Element und die dritte optional ist der Index, um die Suche zu starten. $indexOfArray gibt den ersten Index zurück, bei dem das Element gefunden wird, wenn der Index zum Starten der Suche nicht angegeben ist.


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

Diese Antwort ist am besten für Version 3.4+, aber wenn Sie alte Version verwenden, sollte die Antwort von @BlakesSeven folgen –

4

Es gibt wirklich keine andere Art und Weise („Server-Seite“) als die Verwendung von 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" } 
    } 
) 

Es ist das einzige, was etwas anderes in einer modifizierten Form anders als das Dokument zurückkehrt selbst sowie die benötigte JavaScript-Auswertung, um die Antwort zu ermitteln,

Es gibt leider keinen "nativen" Operator, der dies tun wird.

Sofern Sie dies nicht für echte Aggregationszwecke benötigen, ist es besser, einen ähnlichen "Array-Index-Abgleich" in nativem Code in Ihrem Client durchzuführen, wenn Sie auf "pro Dokument" -Basis arbeiten.

+0

arbeitete wie ein Charme! Aber wie wäre es mit der Leistung bei einer großen Sammlung beim Aufruf von mapReduce? –

+0

@JamesYang Ich denke, dass Sie den Punkt begreifen müssen, dass ich denke, dass Sie das sowieso nicht tun sollten, außer Sie müssen das Ergebnis tatsächlich weiter aggregieren (wie bereits erwähnt). Es gibt keine serverseitige Alternative (wird auch bereits erwähnt), so dass Sie entweder im Fall "serverseitig" mit mapReduce stecken bleiben oder den Index des Arrays pro Dokument im Client verarbeiten (wie bereits empfohlen). –

+0

Mit '{jsMode: true}' Optionen, ist das gut für die Leistung? in Ihrer Erfahrung –

0

In Mongo Shell (in Robomongo auch) die ich tun würde, folgend:

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

oder Sie diesen Code in any_file.js und von der Kommandozeile dann laufen speichern:

mongo your_db any_file.js 

Es produziert etwas wie das:

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

eine Lösung, aber vielleicht nicht practicle –

Verwandte Themen