Kann mit der neuen Firebase-Datenbank Cloud Firestore gezählt werden, wie viele Elemente eine Sammlung enthält?
Wenn ja, wie mache ich das?
firebase
google-cloud-firestore
Guilherme Torres Castro
quelle
quelle
Antworten:
Update (April 2019) - FieldValue.increment (siehe große Sammlungslösung)
Wie bei vielen Fragen lautet die Antwort: Es kommt darauf an .
Sie sollten beim Umgang mit großen Datenmengen im Frontend sehr vorsichtig sein. Firestore sorgt nicht nur dafür, dass sich Ihr Front-End träge anfühlt, sondern berechnet Ihnen auch 0,60 US-Dollar pro Million Lesevorgänge .
Kleine Sammlung (weniger als 100 Dokumente)
Vorsichtig verwenden - Die Benutzererfahrung im Frontend kann beeinträchtigt werden
Die Behandlung am Frontend sollte in Ordnung sein, solange Sie mit diesem zurückgegebenen Array nicht zu viel Logik betreiben.
Mittlere Sammlung (100 bis 1000 Dokumente)
Vorsichtig verwenden - Firestore-Leseaufrufe können viel kosten
Dies am Frontend zu handhaben ist nicht möglich, da es zu viel Potenzial hat, das Benutzersystem zu verlangsamen. Wir sollten diese Logikserverseite behandeln und nur die Größe zurückgeben.
Der Nachteil dieser Methode ist, dass Sie immer noch Firestore-Lesevorgänge aufrufen (entsprechend der Größe Ihrer Sammlung), was Sie auf lange Sicht mehr kosten kann als erwartet.
Cloud-Funktion:
Vorderes Ende:
Große Sammlung (1000+ Dokumente)
Skalierbarste Lösung
Ab April 2019 ermöglicht Firestore jetzt das Inkrementieren von Zählern vollständig atomar und ohne vorheriges Lesen der Daten . Dies stellt sicher, dass wir auch bei gleichzeitiger Aktualisierung aus mehreren Quellen (zuvor mithilfe von Transaktionen gelöst) korrekte Zählerwerte haben, und reduziert gleichzeitig die Anzahl der von uns durchgeführten Datenbanklesevorgänge.
Durch Abhören von gelöschten oder erstellten Dokumenten können wir ein Zählfeld in der Datenbank ergänzen oder daraus entfernen.
Sehen Sie sich die Firestore-Dokumente an - Verteilte Zähler oder werfen Sie einen Blick auf Data Aggregation von Jeff Delaney. Seine Anleitungen sind wirklich fantastisch für alle, die AngularFire verwenden, aber seine Lektionen sollten sich auch auf andere Frameworks übertragen lassen.
Cloud-Funktion:
Jetzt können Sie im Frontend einfach dieses Feld numberOfDocs abfragen, um die Größe der Sammlung zu ermitteln.
quelle
firestore.runTransaction { ... }
Block einschließen sollten. Dies behebt Parallelitätsprobleme beim ZugriffnumberOfDocs
.Am einfachsten ist es, die Größe eines "querySnapshot" zu lesen.
Sie können auch die Länge des docs-Arrays in "querySnapshot" lesen.
Oder wenn ein "querySnapshot" leer ist, lesen Sie den leeren Wert, der einen booleschen Wert zurückgibt.
quelle
db.collection.count()
. Ich denke, sie nur dafür fallen zu lassenSoweit ich weiß, gibt es dafür keine eingebaute Lösung und dies ist derzeit nur im Node SDK möglich. Wenn Sie eine haben
Sie können verwenden
um zu definieren, welches Feld Sie auswählen möchten. Wenn Sie ein leeres select () ausführen, erhalten Sie nur eine Reihe von Dokumentreferenzen.
Beispiel:
db.collection('someCollection').select().get().then( (snapshot) => console.log(snapshot.docs.length) );
Diese Lösung ist nur eine Optimierung für den schlimmsten Fall des Herunterladens aller Dokumente und lässt sich nicht auf große Sammlungen skalieren!
Schauen Sie sich auch Folgendes an:
So erhalten Sie mit Cloud Firestore die Anzahl der Dokumente in einer Sammlung
quelle
select(['_id'])
ist schneller alsselect()
Zählen Sie die Anzahl der Dokumente für große Sammlungen sorgfältig . Die Firestore-Datenbank ist etwas komplex, wenn Sie für jede Sammlung einen vorberechneten Zähler haben möchten.
Code wie dieser funktioniert in diesem Fall nicht:
Der Grund dafür ist, dass jeder Cloud-Firestore-Trigger idempotent sein muss, wie in der Firestore-Dokumentation angegeben: https://firebase.google.com/docs/functions/firestore-events#limitations_and_guarantees
Lösung
Um zu verhindern, dass Ihr Code mehrfach ausgeführt wird, müssen Sie Ereignisse und Transaktionen verwalten. Dies ist meine besondere Art, mit großen Sammlungszählern umzugehen:
Anwendungsfälle hier:
Wie Sie sehen, ist der Schlüssel zum Verhindern der Mehrfachausführung die Eigenschaft eventId im Kontextobjekt . Wenn die Funktion für dasselbe Ereignis mehrmals ausgeführt wurde, ist die Ereignis-ID in allen Fällen dieselbe. Leider müssen Sie "Ereignissammlung" in Ihrer Datenbank haben.
quelle
context.eventId
dies bei mehreren Aufrufen desselben Triggers immer gleich ist? In meinen Tests scheint es konsistent zu sein, aber ich kann keine "offizielle" Dokumentation finden, die dies besagt.Im Jahr 2020 ist dies im Firebase SDK noch nicht verfügbar, es ist jedoch in Firebase Extensions (Beta) verfügbar, es ist jedoch ziemlich komplex einzurichten und zu verwenden ...
Ein vernünftiger Ansatz
Helfer ... (Erstellen / Löschen scheint überflüssig, ist aber billiger als onUpdate)
Exportierte Firestore-Hooks
In Aktion
Die Gebäude Stammsammlung und alle Teilsammlungen werden verfolgt.
Hier unter dem
/counters/
WurzelpfadJetzt werden die Sammlungszahlen automatisch und eventuell aktualisiert! Wenn Sie eine Zählung benötigen, verwenden Sie einfach den Erfassungspfad und stellen Sie ihm ein Präfix voran
counters
.quelle
Ich stimme @Matthew zu, es wird viel kosten, wenn Sie eine solche Abfrage durchführen.
[HINWEIS FÜR ENTWICKLER VOR BEGINN IHRER PROJEKTE]
Da wir diese Situation zu Beginn vorausgesehen haben, können wir tatsächlich eine Sammlung erstellen, nämlich Zähler mit einem Dokument, um alle Zähler in einem Feld mit Typ zu speichern
number
.Beispielsweise:
Aktualisieren Sie für jede CRUD-Operation in der Sammlung das Zählerdokument:
Wenn Sie das nächste Mal die Anzahl der Sammlungen abrufen möchten, müssen Sie nur das Dokumentfeld abfragen / darauf verweisen. [1 Lesevorgang]
Darüber hinaus können Sie den Sammlungsnamen in einem Array speichern. Dies ist jedoch schwierig. Der Zustand des Arrays in der Firebase wird wie folgt angezeigt:
Wenn Sie die Sammlung also nicht löschen möchten, können Sie das Array verwenden, um die Liste der Sammlungsnamen zu speichern, anstatt jedes Mal die gesamte Sammlung abzufragen.
Ich hoffe es hilft!
quelle
Nein, derzeit gibt es keine integrierte Unterstützung für Aggregationsabfragen. Es gibt jedoch einige Dinge, die Sie tun könnten.
Der erste ist hier dokumentiert . Sie können Transaktionen oder Cloud-Funktionen verwenden, um aggregierte Informationen zu verwalten:
Dieses Beispiel zeigt, wie Sie mithilfe einer Funktion die Anzahl der Bewertungen in einer Untersammlung sowie die durchschnittliche Bewertung verfolgen.
Die von jbb erwähnte Lösung ist auch nützlich, wenn Sie Dokumente nur selten zählen möchten. Stellen Sie sicher, dass Sie die
select()
Anweisung verwenden, um zu vermeiden, dass alle Dokumente heruntergeladen werden (das ist viel Bandbreite, wenn Sie nur eine Zählung benötigen).select()
ist derzeit nur in den Server-SDKs verfügbar, sodass die Lösung in einer mobilen App nicht funktioniert.quelle
Es ist keine direkte Option verfügbar. Das kannst du nicht
db.collection("CollectionName").count()
. Im Folgenden finden Sie zwei Möglichkeiten, wie Sie die Anzahl der Dokumente in einer Sammlung ermitteln können.1: - Holen Sie sich alle Dokumente in der Sammlung und dann die Größe. (Nicht die beste Lösung)
Wenn Sie den obigen Code verwenden, entsprechen Ihre gelesenen Dokumente der Größe der Dokumente innerhalb einer Sammlung. Aus diesem Grund muss die Verwendung der obigen Lösung vermieden werden.
2: - Erstellen Sie ein separates Dokument mit in Ihrer Sammlung, in dem die Anzahl der Dokumente in der Sammlung gespeichert wird. (Beste Lösung)
Oben haben wir ein Dokument mit Namenszählungen erstellt, um alle Zählinformationen zu speichern. Sie können das Zählungsdokument folgendermaßen aktualisieren: -
Für den Preis (Document Read = 1) und den schnellen Datenabruf ist die obige Lösung gut.
quelle
Inkrementieren Sie einen Zähler mit admin.firestore.FieldValue.increment :
In diesem Beispiel erhöhen wir
instanceCount
jedes Mal ein Feld im Projekt, wenn ein Dokument zur Untersammlung hinzugefügt wirdinstances
. Wenn das Feld noch nicht vorhanden ist, wird es erstellt und auf 1 erhöht.Die Inkrementierung erfolgt intern, Sie sollten jedoch einen verteilten Zähler verwenden, wenn Sie häufiger als alle 1 Sekunde inkrementieren müssen.
Es ist oft vorzuziehen , zu implementieren
onCreate
undonDelete
nicht ,onWrite
wie Sie rufenonWrite
nach Updates , die bedeuten , dass Sie mehr Geld für unnötige Funktionsaufrufe ausgeben (wenn Sie die Dokumentation in Ihrer Sammlung aktualisieren).quelle
Eine Problemumgehung ist:
Schreiben Sie einen Zähler in ein Firebase-Dokument, den Sie bei jeder Erstellung eines neuen Eintrags innerhalb einer Transaktion erhöhen
Sie speichern die Zählung in einem Feld Ihres neuen Eintrags (dh: Position: 4).
Anschließend erstellen Sie einen Index für dieses Feld (Position DESC).
Sie können mit einer Abfrage ein Überspringen + Limit durchführen. Wo ("Position", "<" x) .OrderBy ("Position", DESC)
Hoffe das hilft!
quelle
Mit all diesen Ideen habe ich eine universelle Funktion erstellt, um alle Gegensituationen (außer Abfragen) zu behandeln.
Dies behandelt Ereignisse, Inkremente und Transaktionen. Das Schöne daran ist, dass Sie den Zähler löschen können, wenn Sie sich über die Genauigkeit eines Dokuments nicht sicher sind (wahrscheinlich noch in der Beta-Phase), damit es beim nächsten Auslöser automatisch addiert wird. Ja, das kostet, also löschen Sie es nicht anders.
Das Gleiche, um die Zählung zu erhalten:
Möglicherweise möchten Sie auch einen Cron-Job (geplante Funktion) erstellen, um alte Ereignisse zu entfernen und Geld beim Datenbankspeicher zu sparen. Sie benötigen mindestens einen Blaze-Plan, und möglicherweise ist eine weitere Konfiguration vorhanden. Sie könnten es zum Beispiel jeden Sonntag um 23 Uhr laufen lassen. https://firebase.google.com/docs/functions/schedule-functions
Dies ist nicht getestet , sollte aber mit ein paar Verbesserungen funktionieren:
Und vergessen Sie nicht, die Sammlungen in firestore.rules zu schützen :
Update: Abfragen
Wenn Sie meiner anderen Antwort hinzufügen möchten, dass Sie auch die Anzahl der Abfragen automatisieren möchten, können Sie diesen geänderten Code in Ihrer Cloud-Funktion verwenden:
Dadurch wird der postsCount im userDocument automatisch aktualisiert . Auf diese Weise können Sie leicht eine andere zu vielen Zählungen hinzufügen. Dies gibt Ihnen nur Ideen, wie Sie Dinge automatisieren können. Ich habe Ihnen auch eine andere Möglichkeit gegeben, die Ereignisse zu löschen. Sie müssen jedes Datum lesen, um es zu löschen, damit Sie es nicht wirklich speichern, um es später zu löschen. Dies verlangsamt nur die Funktion.
quelle
Ich habe eine Weile gebraucht, um dies basierend auf einigen der obigen Antworten zum Laufen zu bringen, also dachte ich, ich würde es für andere teilen. Ich hoffe es ist nützlich.
quelle
Ich habe viel mit verschiedenen Ansätzen versucht. Und schließlich verbessere ich eine der Methoden. Zuerst müssen Sie eine separate Sammlung erstellen und dort alle Ereignisse speichern. Zweitens müssen Sie ein neues Lambda erstellen, das durch die Zeit ausgelöst wird. Dieses Lambda zählt Ereignisse in der Ereignissammlung und löscht Ereignisdokumente. Codedetails im Artikel. https://medium.com/@ihor.malaniuk/how-to-count-documents-in-google-cloud-firestore-b0e65863aeca
quelle
Diese Abfrage führt zur Anzahl der Dokumente.
quelle
quelle