2014-10-31 7 views
9

Ist es möglich, den Positionsoperator '$' in Kombination mit einer Abfrage in einem tief verschachtelten Dokumentarray zu verwenden?

Betrachten Sie das folgende verschachtelte Dokument Definition eines ‚user‘:

{ 
    username: 'test', 
    kingdoms: [ 

     { 
      buildings: [ 

       { 
        type: 'castle' 

       }, 
       { 
        type: 'treasury' 
       }, 

       ... 

      ] 

     }, 

     ... 

    ] 
} 

Wir möchten die ‚Schlösser‘ für einen bestimmten Benutzer zurück z.B. in einer Form:

{ 
    kingdoms: [{ 

     buildings: [{ 

      type: 'castle' 

     }] 

    }] 
} 

Da Sie den $ Operator zweimal nicht verwenden können (https://jira.mongodb.org/browse/server-831) Ich weiß, dass ich nicht auch für ein bestimmtes Reich abfragen kann, so versuche ich, eine Such Erklärung für die n-te Reich zu schreiben .

Dies scheint sinnvoll zu sein, wenn ein tief verschachteltes Unterdokument (Mongodb update deeply nested subdocument) aktualisiert wird, aber ich bin weniger erfolgreich mit der Suche-Abfrage.

kann ich das erste Reich der Gebäude mit der Abfrage zurück:

db.users.findOne(
    { username: 'test' }, 
    { kingdoms: {$slice: [0, 1]}, 'kingdom.buildings': 1 } 
); 

Aber das gibt alle die Gebäude des Königreichs.

Im Anschluss an den einstufig Beispiele für Ortsoperator ich eine Abfrage wie folgt bin versucht:

db.users.findOne(
    { username: 'test', 'kingdoms.buildings.type': 'castle' }, 
    { kingdoms: {$slice: [n, 1]}, 'kingdom.buildings.$': 1 } 
); 

, um in Form zu sein:

db.collection.find({ <array.field>: <value> ...}, { "<array>.$": 1 }) 

wie in der Dokumentation beschrieben http://docs.mongodb.org/manual/reference/operator/projection/positional/#proj.S

Allerdings versagt diese mit dem Fehler:

Positional operator does not match the query specifier 

Vermutlich weil kingdoms.buildings nicht als Array betrachtet wird. Ich habe auch versucht kingdoms.0.buildings

Es ist verwirrend, weil dies für Updates zur Arbeit erscheint (nach Mongodb update deeply nested subdocument)

Habe ich nur die Syntax falsch oder ist dies nicht unterstützt? Wenn ja, gibt es einen Weg, etwas Ähnliches zu erreichen?

Antwort

3

Sie einen Fehler von

db.users.findOne(
    { username: 'test', 'kingdoms.buildings.type': 'castle' }, 
    { kingdoms: {$slice: [n, 1]}, 'kingdom.buildings.$': 1 } 
); 

, weil es einen Fehler Schreibweise ("kingdom.buildings. $" Sollte "Reich s .buildings. $" Sein).
Allerdings kann dieser Weg nicht erreichen, was Sie erwarten.
$ immer auf Reiche auf dem Weg der kingdoms.buildings gerichtet - das erste Array.

Dies ist ein Weg, der in der Lage sein sollte, das Problem zu lösen.
(V2.6+ erforderlichen)

db.c.aggregate([ { 
    $match : { 
     username : 'test', 
     'kingdoms.buildings.type' : 'castle' 
    } 
}, { 
    $project : { 
     _id : 0, 
     kingdoms : 1 
    } 
}, { 
    $redact : { 
     $cond : { 
      "if" : { 
       $or : [ { 
        $gt : [ "$kingdoms", [] ] 
       }, { 
        $gt : [ "$buildings", [] ] 
       }, { 
        $eq : [ "$type", "castle" ] 
       } ] 
      }, 
      "then" : "$$DESCEND", 
      "else" : "$$PRUNE" 
     } 
    } 
} ]).pretty(); 

nur auf das erste Element der Königreich behalten,

db.c.aggregate([ { 
    $match : { 
     username : 'test', 
     'kingdoms.buildings.type' : 'castle' 
    } 
}, { 
    $redact : { 
     $cond : { 
      "if" : { 
       $or : [ { 
        $gt : [ "$kingdoms", [] ] 
       }, { 
        $gt : [ "$buildings", [] ] 
       }, { 
        $eq : [ "$type", "castle" ] 
       } ] 
      }, 
      "then" : "$$DESCEND", 
      "else" : "$$PRUNE" 
     } 
    } 
}, { 
    $unwind : "$kingdoms" 
}, { 
    $group : { 
     _id : "$_id", 
     kingdom : { 
      $first : "$kingdoms" 
     } 
    } 
}, { 
    $group : { 
     _id : "$_id", 
     kingdoms : { 
      $push : "$kingdom" 
     } 
    } 
}, { 
    $project : { 
     _id : 0, 
     kingdoms : 1 
    } 
} ]).pretty(); 
+0

Dank Assistenten - ist es möglich, einfach diese Bedingungen auf die verschiedenen Ebenen der Hierarchie angeben? Sagen Sie zum Argument, ein Königreich hätte einen Schlüssel 'type:" castle "', dann würde es $$ DESCEND sein, obwohl es nicht mit dem Typ eines Gebäudes übereinstimmt. (oder eine ähnliche Situation, wenn dieses Beispiel nicht gültig ist) – Hugheth

+0

@Hugheth, nicht sehr klar über Ihren Standpunkt. Können Sie ein Dokument posten, um es zu beschreiben? – Wizard

+0

Der Hauptunterschied zwischen dieser Antwort und dem _my_ Use Case ist, dass es nicht nach einem einzigen Königreich gefiltert wird - stattdessen gibt es alle Burgen des Benutzers zurück – Hugheth

Verwandte Themen