Angenommen, Sie haben die folgenden Dokumente in meiner Sammlung:
{
"_id":ObjectId("562e7c594c12942f08fe4192"),
"shapes":[
{
"shape":"square",
"color":"blue"
},
{
"shape":"circle",
"color":"red"
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"shapes":[
{
"shape":"square",
"color":"black"
},
{
"shape":"circle",
"color":"green"
}
]
}
Fragen Sie ab:
db.test.find({"shapes.color": "red"}, {"shapes.color": 1})
Oder
db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})
Gibt übereinstimmendes Dokument (Dokument 1) zurück , jedoch immer mit ALLEN Array-Elementen in shapes
:
{ "shapes":
[
{"shape": "square", "color": "blue"},
{"shape": "circle", "color": "red"}
]
}
Ich möchte das Dokument (Dokument 1) jedoch nur mit dem Array erhalten, das Folgendes enthält color=red
:
{ "shapes":
[
{"shape": "circle", "color": "red"}
]
}
Wie kann ich das machen?
aggregate
.db.test.find({}, {shapes: {$elemMatch: {color: "red"}}});
Das neue Aggregation Framework in MongoDB 2.2+ bietet eine Alternative zu Map / Reduce. Mit dem
$unwind
Operator können Sie Ihrshapes
Array in einen Stream von Dokumenten aufteilen, die abgeglichen werden können:Ergebnisse in:
quelle
$elemMatch
ist eine andere Option. Ich bin tatsächlich über eine Google Group-Frage hierher gekommen, bei der $ elemMatch nicht funktionieren würde, da nur die erste Übereinstimmung pro Dokument zurückgegeben wird.{ $project : { shapes : 1 } }
- was zu funktionieren schien und hilfreich wäre, wenn die beiliegenden Dokumente groß wären und Sie nur dieshapes
Schlüsselwerte anzeigen wollten .Eine andere interessante Möglichkeit ist die Verwendung von $ redact , einer der neuen Aggregationsfunktionen von MongoDB 2.6 . Wenn Sie 2.6 verwenden, benötigen Sie kein $ unwind, was bei großen Arrays zu Leistungsproblemen führen kann.
$redact
"schränkt den Inhalt der Dokumente auf der Grundlage der in den Dokumenten selbst gespeicherten Informationen ein" . Es wird also nur innerhalb des Dokuments ausgeführt . Grundsätzlich wird Ihr Dokument von oben nach unten gescannt und überprüft, ob es mit Ihrer aktuellenif
Bedingung übereinstimmt. Wenn eine Übereinstimmung vorliegt$cond
, wird entweder der Inhalt beibehalten ($$DESCEND
) oder entfernt ($$PRUNE
).Im obigen Beispiel wird zuerst
$match
das gesamteshapes
Array zurückgegeben, und $ redact reduziert es auf das erwartete Ergebnis.Beachten Sie, dass dies
{$not:"$color"}
erforderlich ist, da auch das oberste Dokument gescannt wird. Wenn auf der obersten Ebene$redact
keincolor
Feld gefunden wirdfalse
, wird möglicherweise das gesamte Dokument entfernt, das wir nicht möchten.quelle
$match
als Ihre ersteDer Feldauswahlparameter ist auf vollständige Eigenschaften beschränkt. Es kann nicht verwendet werden, um einen Teil eines Arrays auszuwählen, sondern nur das gesamte Array. Ich habe versucht, den $ positional-Operator zu verwenden , aber das hat nicht funktioniert.
Am einfachsten ist es, nur die Formen im Client zu filtern .
Wenn Sie wirklich die richtige Ausgabe direkt von MongoDB benötigen , können Sie die Formen mithilfe einer Kartenreduzierung filtern.
quelle
Besser ist es, wenn Sie das passende Array-Element abfragen, indem
$slice
Sie das signifikante Objekt in einem Array zurückgeben.$slice
ist hilfreich, wenn Sie den Index des Elements kennen, aber manchmal möchten Sie, dass das Array-Element Ihren Kriterien entspricht. Sie können das übereinstimmende Element mit dem$
Operator zurückgeben.quelle
AUSGÄNGE
quelle
Die Syntax für find in mongodb lautet
und die zweite Abfrage, die Sie geschrieben haben, das heißt
In diesem Fall haben Sie den
$elemMatch
Operator im Abfrageteil verwendet. Wenn Sie diesen Operator im Projektionsteil verwenden, erhalten Sie das gewünschte Ergebnis. Sie können Ihre Anfrage als aufschreibenDadurch erhalten Sie das gewünschte Ergebnis.
quelle
"shapes.color":"red"
im Abfrageparameter (dem ersten Parameter der Suchmethode) keine Notwendigkeit besteht. Sie können es durch ersetzen{}
und die gleichen Ergebnisse erzielen.Vielen Dank an JohnnyHK .
Hier möchte ich nur eine komplexere Verwendung hinzufügen.
quelle
Sie müssen nur die Abfrage ausführen
Ausgabe dieser Abfrage ist
Wie erwartet wird das genaue Feld des Arrays angezeigt, das der Farbe entspricht: 'rot'.
quelle
zusammen mit $ project ist es angemessener, andere weise übereinstimmende Elemente zusammen mit anderen Elementen im Dokument zu kombinieren.
quelle
Ebenso können Sie für das Vielfache finden
quelle
$match
Reduzieren Sie den Platz,$filter
behalten Sie dann das gewünschte Feld bei und überschreiben Sie das Eingabefeld (verwenden Sie die Ausgabe von$filter
on field,shapes
um darauf$project
zurückzugreifenshapes
. Stilhinweis: Verwenden Sie den Feldnamen am besten nicht als dasas
Argument, weil das später zu Verwirrung mit$$shape
und führen kann$shape
. Ich bevorzugezz
als dasas
Feld, weil es wirklich auffällt.quelle
Verwenden Sie die Aggregationsfunktion und
$project
, um ein bestimmtes Objektfeld im Dokument abzurufenErgebnis:
quelle
Obwohl die Frage vor 9,6 Jahren gestellt wurde, war dies für zahlreiche Menschen, von denen ich einer von ihnen bin, eine immense Hilfe. Vielen Dank an alle für all Ihre Fragen, Hinweise und Antworten. Ich habe festgestellt, dass die folgende Methode auch zum Projizieren anderer Felder im übergeordneten Dokument verwendet werden kann. Dies kann für jemanden hilfreich sein.
Für das folgende Dokument musste herausgefunden werden, ob für einen Mitarbeiter (emp # 7839) die Urlaubshistorie für das Jahr 2020 festgelegt wurde. Die Urlaubshistorie wird als eingebettetes Dokument im übergeordneten Mitarbeiterdokument implementiert.
quelle