MongoDB Projektion Geschachtelte Arrays
Habe ich eine Sammlung "Konten", die enthält Dokumente, die ähnlich wie diese Struktur:
{
"email" : "[email protected]",
"groups" : [
{
"name" : "group1",
"contacts" : [
{ "localId" : "c1", "address" : "some address 1" },
{ "localId" : "c2", "address" : "some address 2" },
{ "localId" : "c3", "address" : "some address 3" }
]
},
{
"name" : "group2",
"contacts" : [
{ "localId" : "c1", "address" : "some address 1" },
{ "localId" : "c3", "address" : "some address 3" }
]
}
]
}
Über
q = { "email" : "[email protected]", "groups" : { $elemMatch: { "name" : "group1" } } }
p = { "groups.name" : 0, "groups" : { $elemMatch: { "name" : "group1" } } }
db.accounts.find( q, p ).pretty()
Werde ich erfolgreich bekommen nur die Gruppe von einem angegebenen Konto bin ich interessiert.
Frage: Wie kann ich eine begrenzte Liste "Kontakte" innerhalb einer bestimmten "Gruppe" einer bestimmten "Konto"? Nehmen wir an ich habe die folgenden Argumente:
- Konto: E-Mail - "[email protected]"
- Gruppe: - name - "Gruppe1"
- Kontakt: array von localIds - [ "c1", "c3", "Nicht existierende id" ]
Gegeben, diese Argumente hätte ich gerne Folgendes Ergebnis:
{
"groups" : [
{
"name" : "group1", (might be omitted)
"contacts" : [
{ "localId" : "c1", "address" : "some address 1" },
{ "localId" : "c3", "address" : "some address 3" }
]
}
]
}
Ich brauche nichts anderes, abgesehen von der daraus resultierenden Kontakte.
Ansätze
Alle Anfragen versuchen zu Holen, nur ein passender Kontakt, anstatt eine Liste der passenden Kontakte, der Einfachheit halber.
Ich habe versucht, die folgenden Abfragen ohne Erfolg:
p = { "groups.name" : 0, "groups" : { $elemMatch: { "name" : "group1", "contacts" : { $elemMatch: { "localId" : "c1" } } } } }
p = { "groups.name" : 0, "groups" : { $elemMatch: { "name" : "group1", "contacts.localId" : "c1" } } }
not working: returns whole array or nothing depending on localId
p = { "groups.$" : { $elemMatch: { "localId" : "c1" } } }
error: {
"$err" : "Can't canonicalize query: BadValue Cannot use $elemMatch projection on a nested field.",
"code" : 17287
}
p = { "groups.contacts" : { $elemMatch: { "localId" : "c1" } } }
error: {
"$err" : "Can't canonicalize query: BadValue Cannot use $elemMatch projection on a nested field.",
"code" : 17287
}
Jede Hilfe ist willkommen!
- Ein weiteres für die Zuschauer. Dies ist, wie Sie "Fragen" hier. Zeigen Sie, was Sie versucht haben, und geben Sie bestimmte Fehler. Gute Möglichkeit zu Fragen.
- Gute Frage.
Du musst angemeldet sein, um einen Kommentar abzugeben.
2017 Update
Solche gut gestellten Frage verdient eine moderne Antwort. Das Sortieren von array-Filterung angeforderte überhaupt gemacht werden kann, in der modernen MongoDB-releases post 3.2 über einfach
$match
und$project
pipeline-Stufen, ähnlich wie die ursprünglichen nur Abfrage operation beabsichtigt.Das macht die Verwendung des
$filter
und$anzeigen
- Betreiber, um nur die Elemente aus den arrays als würde die Bedingungen erfüllen, und ist weit besser für die performance als die Verwendung von$entspannen
. Da die pipeline-Stufen effektiv, spiegeln die Struktur der "Abfrage" und "Projekt" aus einer.find()
Betrieb, die Leistung ist hier im Grunde auf eine Stufe mit solchen und Betrieb.Hinweis, dass dort, wo die Absicht besteht, tatsächlich zu arbeiten "in allen Dokumenten" zu bringen details zusammen aus "mehrere" Dokumente eher als "eins", dann wäre dies erfordert in der Regel einige Art der
$unwind
Betrieb, um so zu tun, als solche Aktivierung der array-Elemente zugegriffen werden, die für "Gruppierung".Dies ist im Grunde der Ansatz:
Ist dies "array Filter" auf mehr als ein einzelnes Spiel, das die grundlegenden projektionsmöglichkeiten von
.find()
nicht.Haben Sie "verschachtelten" arrays daher benötigen Sie
$entspannen
zweimal. Zusammen mit den anderen Operationen.null
übereinstimmung tritt auf, wenn das Feld gar nicht vorhanden ist oder tatsächlich enthält, dass der Wert in irgendeiner form einzelner Wert oder ein array ist. 99,999% der Zeit, die Sie nicht wollen, zu Fragen, für einenull
match und einfach akzeptieren, dass "gelieferten Werte" sind alles, was Sie brauchen. Ich würde stark vorschlagen, Sie Folgen, und nutzen Sie einfach die unterschiedlichen Werte ohnenull
.Könnten Sie die $entspannen Betreiber des aggregation framework.
Zum Beispiel:
Sollte geben das folgende Ergebnis:
Wenn Sie möchten, dass nur ein Objekt, dann können Sie die $Gruppe Betreiber.