Ich versuche, MongoDB zu lernen, und es war bisher großartig. Jedoch bin ich in eine Situation geraten und ich bin mir nicht sicher, wie man es löst. Hoffentlich konnte mir jemand helfen und danke im Voraus.
Ich wollte Datensätze erhalten, dass der (vollständige) Array-Wert innerhalb der Abfrage liegt. Zum Beispiel:
Datensatz 1:
%Vor%Datensatz 2:
%Vor%Datensatz 3:
%Vor%Dann hätte ich eine Abfrage wie
%Vor% weil ich Mango, Sojamilch und Erdbeere habe. Also wollte ich wissen, welche Shakes ich machen kann. Anscheinend gibt das nichts zurück, da die Abfrage keine zusätzlichen Daten enthalten kann. Wenn ich $in
benutze, dann kommen alle zurück, aber ich kann keinen Mango-Bananen-Shake machen, weil ich keine Banane habe.
Was ich also nur brauche, ist der erste und der letzte. Irgendeine Idee? Schätze es:)
Ich konnte mir keinen Weg vorstellen, dies mit Find zu tun. Aber Sie könnten es mit einem mapReduce machen.
Ihre Kartenfunktion würde die Inhaltsstoffe des aktuell untersuchten Dokuments wiederholen und nur dann ausgeben, wenn alle Felder Zutaten sind, die Sie haben. Sie benötigen hierfür keine Reduce-Funktion, daher sollte der Schlüssel der ausgegebenen Werte die _id der Getränkedokumente sein.
Wenn die Schlüssel eindeutig sind, sollte die reduce-Funktion niemals aufgerufen werden (die reduce-Funktion wird verwendet, um zu bestimmen, was passiert, wenn mehrere Werte für denselben Schlüssel ausgegeben werden). Ich denke nicht, dass Sie die Reduce-Funktion einfach weglassen können, also sollten Sie eine schreiben, die nur das erste Element des Werte-Arrays zurückgibt.
Map reduce funktioniert, wenn Sie möchten, oder Sie können einfach $ und mit einer Bedingung für jeden Ihrer Bestandteile verwenden:
Ich habe $ und vorher für ähnliche Abfrage benötigt. Leider muss dies in beiden Fällen jedes einzelne Rezeptdokument bei jeder Abfrage überprüfen, was schwerwiegende Auswirkungen auf die Leistung hat, wenn Ihre Sammlung umfangreich wird.
Dies kann besser mit einer relationalen Datenbank gehandhabt werden. Zumindest sollten Sie in Betracht ziehen, einen separaten abfragbaren Index von Zutaten mit einer Karte zu den Rezept-IDs zu führen, die sie verwenden. Dann könnten Sie nur die Zutaten, die Sie haben, abrufen und die Schnittmenge der Rezepte in Code übernehmen. Da dies tatsächlich etwas ist, was eine relationale Datenbank für Sie tun kann, ist es hier einfach die bessere Wahl.
Sie können Punktnotation verwenden, um auf bestimmte Elemente des Arrays zuzugreifen und sie zu überprüfen dass jedes Element ist $in
Ihre Liste verfügbarer Zutaten und Sie könnten eine $and
Abfrage erstellen, um dies für jedes Element in dem Dokument zu tun, ABER natürlich das wird nicht funktionieren , da Sie nicht tun wissen, wie viele Elemente in der Zutatenliste jedes Rezepts enthalten sind.
Eine Lösung für dieses Problem ist das Hinzufügen eines Arrays zu jedem Dokument, das eine feste Größe hat (vielleicht 3 Elemente), in die Sie die n-am häufigsten verwendeten Bestandteile aus dem Rezept einfügen (mit Wiederholungen, falls erforderlich, um das Array zu füllen) ). Jetzt können Sie eine Abfrage mit $and
und $in
für jedes Element dieses Arrays durchführen. Dies wird alle Rezepte finden, die "möglich" sein könnten, und da Sie die am wenigsten verbreiteten Zutaten gespeichert haben, sollte es einen guten Job machen, um Rezepte herauszufiltern, die Sie nicht herstellen können. Sie können dann den letzten Filter clientseitig machen.
Manchmal kann das Hinzufügen einer anderen Darstellung der Daten ein guter Weg sein, um ein schwieriges Abfrageproblem wie dieses zu lösen, und manchmal kann eine Kombination aus server- und clientseitiger Filterung angebracht sein.
Sie können eine JavaScript-Funktion als Suchparameter verwenden. Ich denke jedoch, dass MapReduce aufgrund der Skalierbarkeit und der allgemeinen Unruhe beim Einfügen von Benutzereingaben in Code, der ausgeführt wird, eine viel elegantere Lösung darstellt.
Hier ist eine Beispielabfrage, die erstellt würde. Grundsätzlich filtert es die Zutaten des Artikels und prüft, ob die gefilterte Liste die gleiche Länge wie die ursprüngliche Zutatenliste hat:
%Vor%Es gibt keinen direkten Weg, dies zu tun. Sie können eine einfache Javascript-Funktion erstellen, um Ihre Abfrage zu lösen, indem Sie jedes Dokument und die Überprüfung der Array-Zutaten hat alle drei Zutaten.
%Vor%Um eine neue Idee zu bringen, falls Sie bereits alle Zutaten kennen. Zum Beispiel sind die möglichen Zutaten nur 5:
%Vor%Und Sie haben weder Banane noch Ananas
Eine Möglichkeit besteht darin, nach den Zutaten zu suchen, die Sie nicht haben:
%Vor%Dies gibt alle Dokumente zurück, die keine Zutat haben, die Sie nicht haben, also die Rezepte mit Zutaten, die Sie tatsächlich haben.
Angenommen, Sie sind mit den Vorbehalten für die Verwendung des Operators $where
einverstanden Sie können es in Kombination mit Array.prototype.some und Array.prototype.every , um die gewünschten Ergebnisse zu erhalten Ergebnisse.
Das sieht nach einer JavaScript-spezifischen Lösung aus, ist es aber nicht. Das Javascript wird direkt in Mongo (V8) injiziert. Alle Sprachtreiber sollten dies unterstützen. Ich weiß zumindest, dass PHP tut.
Sie sollten in der Lage sein, diesen Code direkt in die Mongo REPL und erhalten Sie die Ergebnisse, die Sie erwarten (klopfen auf Holz).
Wenn Ihre Milchshake-Datenbank über das hinausgeht, was $where
Ihnen geben kann, Aggregation Framework ist dein Freund.
Tags und Links mongodb