it-swarm.com.de

Wie kann man ein "Array von Objekten" mit Firestore aktualisieren?

Ich versuche gerade Firestore, und ich bleibe bei etwas sehr Einfachem: "Aktualisierung eines Arrays (auch als Filialdokument bezeichnet)".

Meine DB-Struktur ist sehr einfach. Zum Beispiel:

proprietary: "John Doe"
sharedWith:
  [
    {who: "[email protected]", when:timestamp}
    {who: "[email protected]", when:timestamp}
  ]

Ich versuche (ohne Erfolg), neue Datensätze in das shareWith-Array von Objekten zu verschieben.

Ich habe es versucht:

// With SET
firebase.firestore()
.collection('proprietary')
.doc(docID)
.set(
  { sharedWith: [{ who: "[email protected]", when: new Date() }] },
  { merge: true }
)

// With UPDATE
firebase.firestore()
.collection('proprietary')
.doc(docID)
.update({ sharedWith: [{ who: "[email protected]", when: new Date() }] })

Keiner funktioniert .. Diese Abfragen überschreiben mein Array.

Die Antwort könnte einfach sein, aber ich konnte sie nicht finden ...

Vielen Dank

33
nerotulip

Edit 08/13/2018: In Cloud Firestore werden jetzt native Array-Vorgänge unterstützt. Dougs Antwort unten.


Derzeit ist es nicht möglich, ein einzelnes Array-Element in Cloud Firestore zu aktualisieren (oder ein einzelnes Element hinzuzufügen/zu entfernen). 

Dieser Code hier:

firebase.firestore()
.collection('proprietary')
.doc(docID)
.set(
  { sharedWith: [{ who: "[email protected]", when: new Date() }] },
  { merge: true }
)

Dies bedeutet, das Dokument auf proprietary/docID zu setzen, so dass sharedWith = [{ who: "[email protected]", when: new Date() }, aber keine vorhandenen Dokumenteigenschaften beeinflusst. Dies ist dem update()-Aufruf, den Sie angegeben haben, sehr ähnlich. Der set()-Aufruf mit create the document ist jedoch nicht vorhanden, wenn der update()-Aufruf fehlschlägt.

Sie haben also zwei Möglichkeiten, um das zu erreichen, was Sie wollen.

Option 1 - Setze das ganze Array

Rufen Sie set() mit dem gesamten Inhalt des Arrays auf. Dazu müssen zuerst die aktuellen Daten aus der DB gelesen werden. Wenn Sie über gleichzeitige Aktualisierungen besorgt sind, können Sie all dies in einer Transaktion durchführen.

Option 2 - Verwenden Sie eine Unterkollektion

Sie können sharedWith zu einer Unterkollektion des Hauptdokuments machen. Dann würde das Hinzufügen eines einzelnen Elements folgendermaßen aussehen:

firebase.firestore()
  .collection('proprietary')
  .doc(docID)
  .collection('sharedWith')
  .add({ who: "[email protected]", when: new Date() })

Dies bringt natürlich neue Einschränkungen mit sich. Sie könnten keine __.-Dokumente abfragen, je nachdem, für wen sie freigegeben sind, und __........ Das Dokument und alle sharedWith-Daten in einem einzigen Vorgang abrufen.

34
Sam Stern

Firestore verfügt jetzt über zwei Funktionen, mit denen Sie ein Array aktualisieren können, ohne das gesamte Objekt neu schreiben zu müssen.

Link: https://firebase.google.com/docs/firestore/manage-data/add-data , insbesondere https://firebase.google.com/docs/firestore/manage-data/add -data # update_elements_in_an_array

Elemente in einem Array aktualisieren

Wenn Ihr Dokument ein Array-Feld enthält, können Sie arrayUnion () und .__ verwenden. arrayRemove () zum Hinzufügen und Entfernen von Elementen. arrayUnion () fügt Elemente hinzu zu einem Array, aber nur Elemente, die noch nicht vorhanden sind. arrayRemove () Entfernt alle Instanzen jedes angegebenen Elements.

47
Doug Galante

Sie können eine Transaktion ( https://firebase.google.com/docs/firestore/manage-data/transactions ) verwenden, um das Array abzurufen.

    const booking = { some: "data" };
    const userRef = this.db.collection("users").doc(userId);

    this.db.runTransaction(transaction => {
        // This code may get re-run multiple times if there are conflicts.
        return transaction.get(userRef).then(doc => {
            if (!doc.data().bookings) {
                transaction.set({
                    bookings: [booking]
                });
            } else {
                const bookings = doc.data().bookings;
                bookings.Push(booking);
                transaction.update(userRef, { bookings: bookings });
            }
        });
    }).then(function () {
        console.log("Transaction successfully committed!");
    }).catch(function (error) {
        console.log("Transaction failed: ", error);
    });
9

Tut mir leid, dass ich zu spät gefeiert habe, aber Firestore hat es bereits im August 2018 gelöst. Wenn Sie immer noch danach suchen, finden Sie hier alle Probleme in Bezug auf Arrays.

https://firebase.googleblog.com/2018/08/better-arrays-in-cloud-firestore.htmlOffizieller Blogbeitrag

array-includes, arrayRemove, arrayUnion zum Prüfen, Entfernen und Aktualisieren von Arrays. Ich hoffe es hilft.

3
Guru

Um auf Sam Sterns Antwort aufzubauen, gibt es auch eine 3rd-Option, die die Dinge für mich einfacher machte und die, was Google eine Map nennt, was im Wesentlichen ein Wörterbuch ist.

Ich denke, ein Wörterbuch ist für den Anwendungsfall, den Sie beschreiben, viel besser. Normalerweise verwende ich Arrays für Dinge, die nicht wirklich zu viel aktualisiert werden, daher sind sie mehr oder weniger statisch. Aber für Dinge, die häufig geschrieben werden, insbesondere Werte, die für Felder aktualisiert werden müssen, die mit anderen Elementen in der Datenbank verknüpft sind, lassen sich Wörterbücher viel einfacher pflegen und verwenden. 

Für Ihren speziellen Fall würde die DB-Struktur also folgendermaßen aussehen:

proprietary: "John Doe"
sharedWith:{
  whoEmail1: {when: timestamp},
  whoEmail2: {when: timestamp}
}

Auf diese Weise können Sie Folgendes tun:

var whoEmail = '[email protected]';

var sharedObject = {};
sharedObject['sharedWith.' + whoEmail + '.when'] = new Date();
sharedObject['merge'] = true;

firebase.firestore()
.collection('proprietary')
.doc(docID)
.update(sharedObject);

Der Grund für die Definition des Objekts als Variable besteht darin, dass die Verwendung von 'sharedWith.' + whoEmail + '.when' direkt in der set-Methode zu einem Fehler führt, zumindest wenn es in einer Node.js-Cloud-Funktion verwendet wird.

2
Horea

So habe ich es geschafft. Ich hoffe, es hilft Ihnen allen, da ich es als eine bessere Lösung sehe. Hier möchte ich den Status der Aufgabe von Öffnen (Schließen = Falsch) in Schließen (Schließen = Wahr) ändern, während alles andere im Objekt gleich bleibt .

closeTask(arrayIndex) {
        let tasks = this.lead.activityTasks;

        const updatedTask = {
          name: tasks[arrayIndex].name,
          start: tasks[arrayIndex].start,
          dueDate:tasks[arrayIndex].dueDate,
          close: true, // This is what I am changing.
        };
        tasks[arrayIndex] = updatedTask;

        const data = {
          activityTasks: tasks
        };

        this.leadService.updateLeadData(data, this.lead.id);
    }

und hier ist der Dienst, der es tatsächlich aktualisiert

 public updateLeadData(updateData, leadId) {
    const leadRef: AngularFirestoreDocument<LeadModel> = this.afs.doc(
      `leads/${leadId}`);

return leadRef.update(updateData);
}
1
Leandrit Ferizi

Betrachten Sie John Doe als Dokument und nicht als Sammlung

Geben Sie ihm eine Sammlung von Dingen und Dingen

Anschließend können Sie die gemeinsam genutzten Dinge von John Doe in dieser parallel sortingsSharedWithOthers-Sammlung zuordnen und abfragen. 

proprietary: "John Doe"(a document)

things(collection of John's things documents)

thingsSharedWithOthers(collection of John's things being shared with others):
[thingId]:
    {who: "[email protected]", when:timestamp}
    {who: "[email protected]", when:timestamp}

then set thingsSharedWithOthers

firebase.firestore()
.collection('thingsSharedWithOthers')
.set(
{ [thingId]:{ who: "[email protected]", when: new Date() } },
{ merge: true }
)

Andere als die oben genannten Antworten. Dies wird es tun . Mit Angular 5 und AngularFire2. oder benutze firebase.firestore () anstelle von this.afs

  // say you have have the following object and 
  // database structure as you mentioned in your post
  data = { who: "[email protected]", when: new Date() };

  ...othercode


  addSharedWith(data) {

    const postDocRef = this.afs.collection('posts').doc('docID');

    postDocRef.subscribe( post => {

      // Grab the existing sharedWith Array
      // If post.sharedWith doesn`t exsit initiated with empty array
      const foo = { 'sharedWith' : post.sharedWith || []};

      // Grab the existing sharedWith Array
      foo['sharedWith'].Push(data);

      // pass updated to fireStore
      postsDocRef.update(foo);
      // using .set() will overwrite everything
      // .update will only update existing values, 
      // so we initiated sharedWith with empty array
    });
 }  
0
Jassi

Wenn jemand nach einer Java firestore sdk-Lösung sucht, um Elemente im Array-Feld hinzuzufügen:

List<String> list = Java.util.Arrays.asList("A", "B");
Object[] fieldsToUpdate = list.toArray();
DocumentReference docRef = getCollection().document("docId");
docRef.update(fieldName, FieldValue.arrayUnion(fieldsToUpdate));

So löschen Sie Elemente aus dem Array-Benutzer: FieldValue.arrayRemove()

0
A_01