166 votes

Comment mettre à jour un "tableau d'objets" avec Firestore ?

Je suis en train d'essayer Firestore, et je suis bloqué sur quelque chose de très simple : "mettre à jour un tableau (aka un sous-document)".

La structure de ma base de données est très simple. Par exemple :

proprietary: "John Doe",
sharedWith:
  [
    {who: "first@test.com", when:timestamp},
    {who: "another@test.com", when:timestamp},
  ],

J'essaye (sans succès) de pousser les nouveaux enregistrements dans le fichier shareWith réseau d'objets.

J'ai essayé :

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

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

Aucun ne fonctionne. Ces requêtes écrasent mon tableau.

La réponse est peut-être simple, mais je ne l'ai pas trouvée...

1 votes

Hé, tu as trouvé ? Je n'arrive toujours pas à trouver une réponse.

0 votes

Pour Android, c'est aussi simple que Comment mettre à jour un tableau d'objets dans Firestore ? .

207voto

Doug Galante Points 901

Firestore dispose désormais de deux fonctions qui vous permettent de mettre à jour un tableau sans avoir à réécrire l'ensemble.

Lien : https://firebase.google.com/docs/firestore/manage-data/add-data et plus particulièrement https://firebase.google.com/docs/firestore/manage-data/add-data#update_elements_in_an_array

Mise à jour des éléments d'un tableau

Si votre document contient un champ de type tableau, vous pouvez utiliser arrayUnion() et arrayRemove() pour ajouter et supprimer des éléments. arrayUnion() ajoute des éléments à un tableau mais à un tableau, mais seulement les éléments qui ne sont pas déjà présents. arrayRemove() supprime toutes les instances de chaque élément donné.

115 votes

Existe-t-il un moyen de mettre à jour un index spécifique du tableau ?

2 votes

Comment utiliser cette fonctionnalité de mise à jour des tableaux avec "react-native-firebase" ? (Je ne trouve pas cela dans la documentation officielle de react-native-firebase).

8 votes

@ArturCarvalho Non, la raison en est expliquée dans cette vidéo. youtube.com/

109voto

hatboysam Points 1191

Modifier le 13/08/2018 : Il existe désormais une prise en charge des opérations de tableau natives dans Cloud Firestore. Voir Réponse de Doug ci-dessous.


Il n'existe actuellement aucun moyen de mettre à jour un seul élément de tableau (ou d'ajouter/supprimer un seul élément) dans Cloud Firestore.

Ce code ici :

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

Cela dit de mettre le document à proprietary/docID tal que sharedWith = [{ who: "third@test.com", when: new Date() } mais pour ne pas affecter les propriétés existantes du document. C'est très similaire à la méthode update() l'appel que vous avez fourni, mais le set() avec la création du document s'il n'existe pas alors que l'appel de l update() l'appel échouera.

Vous avez donc deux possibilités pour obtenir ce que vous voulez.

Option 1 - Définir l'ensemble du tableau

Appelez set() avec le contenu entier du tableau, ce qui nécessitera de lire d'abord les données actuelles de la BD. Si vous êtes préoccupé par les mises à jour simultanées, vous pouvez faire tout cela dans une transaction.

Option 2 - Utiliser une sous-collection

Vous pourriez faire sharedWith une sous-collection du document principal. Ensuite, l'ajout d'un seul élément ressemblerait à ceci :

firebase.firestore()
  .collection('proprietary')
  .doc(docID)
  .collection('sharedWith')
  .add({ who: "third@test.com", when: new Date() })

Bien sûr, cela s'accompagne de nouvelles limitations. Vous ne serez pas en mesure d'interroger documents en fonction de la personne avec qui ils sont partagés, et vous ne pourrez pas non plus obtenir le document et tous les sharedWith en une seule opération.

11 votes

C'est tellement frustrant... mais merci de me dire que je ne suis pas folle.

67 votes

C'est un gros inconvénient, Google doit le corriger au plus vite.

6 votes

La réponse de @DougGalante indique que cela a été corrigé. Utilisez le arrayUnion méthode.

23voto

Gabriel McCallin Points 131

Vous pouvez utiliser une transaction ( https://firebase.google.com/docs/firestore/manage-data/transactions ) pour obtenir le tableau, le pousser sur celui-ci et ensuite mettre à jour le document :

    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);
    });

2 votes

À l'instruction if, vous devriez le changer en ceci, car il vous manque l'instruction documentReference ajouter userRef comme indiqué : transaction.set(userRef, { bookings: [booking] });

0 votes

Cela va réécrire le tableau entier

10voto

Guru Points 126

Désolé d'intervenir tardivement, mais Firestore a résolu le problème en août 2018. Si vous le cherchez toujours, voici tous les problèmes résolus en ce qui concerne les tableaux.

https://firebase.googleblog.com/2018/08/better-arrays-in-cloud-firestore.html Article de blog officiel

array-contains, arrayRemove, arrayUnion pour vérifier, supprimer et mettre à jour les tableaux. J'espère que cela vous aidera.

6voto

Horea Points 91

S'appuyer sur La réponse de Sam Stern il y a aussi un 3ème option qui m'a facilité les choses, c'est d'utiliser ce que Google appelle une carte, qui est essentiellement un dictionnaire.

Je pense qu'un dictionnaire est bien meilleur pour le cas d'utilisation que vous décrivez. J'utilise généralement les tableaux pour les éléments qui ne sont pas trop mis à jour, ils sont donc plus ou moins statiques. Mais pour les choses qui sont souvent écrites, en particulier les valeurs qui doivent être mises à jour pour les champs qui sont liés à quelque chose d'autre dans la base de données, les dictionnaires s'avèrent beaucoup plus faciles à maintenir et à utiliser.

Ainsi, pour votre cas spécifique, la structure de la base de données ressemblerait à ceci :

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

Cela vous permettra de faire ce qui suit :

var whoEmail = 'first@test.com';

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

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

La raison pour laquelle l'objet est défini en tant que variable est que l'utilisation de la fonction 'sharedWith.' + whoEmail + '.when' directement dans la méthode set entraînera une erreur, du moins lorsqu'elle est utilisée dans une fonction cloud de Node.js.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X