2016-04-06 11 views
4

Ich möchte ein Feld im Array suchen und wissen, was ist der Index dieses Feldes im Array ist es möglich, es zu finden? Beispiel:DOC nach relativen Array-Element-Positionen suchen

doc1: {id:123, hobby:['chess','cards','dance']} 
doc2: {id:123, hobby:['cards','dance','chess']} 

ich nur das Dokument gesucht werden soll, die chess und cards aber nur den einen hat die chess vor card hat. Also im Fall doc1.

Antwort

3

Sie können dies mit dem $where Operator, es mit dem Betreiber $all Kopplung zu halten vernünftigerweise performant:

db.test.find({ 
    // Find all the docs where hobby contains both 'cards' and 'chess' 
    hobby: {$all: ['cards', 'chess']}, 
    // Of those, run this $where query that evaluates the indexes of the matched elements 
    $where: "this.hobby.indexOf('cards') > this.hobby.indexOf('chess')" 
}) 

einen Index hinzufügen auf hobby für die beste Leistung.

0

Für die beste Leistung, die Sie tatsächlich .aggregate() mit einer $match Bühne für eine „Abfrage“ mögliche Übereinstimmungen zu den Dokumenten zu verengen, die $all die Elemente in dem Array enthalten verwenden würden, und $redact von den übrigen Ergebnissen filtern:

db.test.aggregate([ 
    { "$match": { "hobby": { "$all": [ "chess", "cards" ] } } }, 
    { "$redact": { 
    "$cond": { 
     "if": { 
     "$eq": [ 
      { "$filter": { 
       "input": "$hobby", 
       "as": "hobby", 
       "cond": { 
       "$or": [ 
        { "$eq": [ "$$hobby", "chess" ] }, 
        { "$eq": [ "$$hobby", "cards" ] } 
       ] 
       } 
      }}, 
      ["chess","cards"] 
     ] 
     }, 
     "then": "$$KEEP", 
     "else": "$$PRUNE" 
    }  
    }} 
]) 

der Grund, dass, weil $filter funktioniert, ist nur die Elemente zurückgeben können, die die Bedingungen hier angegebenen übereinstimmen, und gibt sie „in derselben Reihenfolge“, in dem sie in dem Originaldokument gespeichert werden.

Once „gefiltert“ nach unten, sollte das Array dann eine genaue Übereinstimmung für den Inhalt ["chess","cards"], wenn in der Tat jener Elemente in der ursprünglichen Anordnung in dieser Reihenfolge waren.

Beachten Sie, dass, während es "einfacher" aussehen kann, Sie "set operators" nicht verwenden können, um dies zu testen, da "Sets" tatsächlich nicht als bestellt angesehen werden.

Sie brauchen also etwas, das die Reihenfolge aufrechterhält, und $filter ist wirklich die einzige Sache, die dies mit Array-Inhalt in einer effizienten Weise tun kann. Die Lösung beschränkt sich in der Tat auf eine Version von MongoDB 3.2 oder höher, um tatsächlich zu funktionieren.

Für ältere Versionen finden Sie in die answer from JohnnyHK mit $where zu verwenden $all einen .indexOf() Test auf den Array-Elementen als zusätzliche Filter anzuwenden.

Aber wenn Sie MongoDB 3.2 mit den verfügbaren Operatoren haben, dann laufen die systemeigenen codierten Operationen, die für das Aggregationsframework verfügbar sind, viel schneller als die JavaScript-Auswertung $where und sollten bevorzugt verwendet werden.