316 votes

À quoi sert le type de données "Référence" de Firebase Firestore ?

Je suis en train d'explorer le nouveau Firebase Firestore et il contient un type de données appelé reference . Je ne vois pas très bien à quoi cela sert.

  • C'est comme une clé étrangère ?
  • Peut-on l'utiliser pour pointer vers une collection qui se trouve ailleurs ?
  • Si reference est une référence réelle, puis-je l'utiliser pour des requêtes ? Par exemple, puis-je avoir une référence qui pointe directement vers l'utilisateur, au lieu de stocker l'ID utilisateur dans un champ de texte ? Et puis-je utiliser cette référence d'utilisateur pour effectuer des requêtes ?

32 votes

Je pense que cette vidéo de l'équipe de firebase vous explique tout : youtube.com/watch?v=Elg2zDVIcLo (regarder à partir de 4:36)

25 votes

1 votes

Je n'aime pas imbriquer les collections dans firebase pour de multiples raisons. Si pour une raison quelconque, vous avez une autre collection de niveau racine que vous avez besoin de forer tout le chemin vers le bas sur une collection racine sœur ; disons 4 niveaux pour obtenir un document. Ceci est rendu beaucoup plus facile en utilisant des références et en utilisant simplement db.doc('some_saved_ref') plutôt que de faire correspondre tous les identifiants à nouveau... à partir de l'autre collection racine.

207voto

Ben Cochrane Points 2026

J'ajoute ci-dessous ce qui a fonctionné pour moi en utilisant des références dans Firestore.

Comme le disent les autres réponses, c'est comme une clé étrangère. L'attribut de référence ne renvoie pas les données du document de référence cependant. Par exemple, j'ai une liste de produits, avec une référence userRef comme l'un des attributs du produit. Obtenir la liste des produits, me donne la référence de l'utilisateur qui a créé ce produit. Mais cela ne me donne pas les détails de l'utilisateur dans cette référence. J'ai utilisé d'autres back-end comme des services avec des pointeurs avant qui ont un drapeau "populate : true" qui donne les détails de l'utilisateur au lieu de juste l'id de référence de l'utilisateur, ce qui serait génial à avoir ici (espérons une amélioration future).

Voici un exemple de code que j'ai utilisé pour définir la référence ainsi que pour obtenir la liste de la collection de produits puis pour obtenir les détails de l'utilisateur à partir de l'id de référence de l'utilisateur donné.

Définit une référence sur une collection :

let data = {
  name: 'productName',
  size: 'medium',
  userRef: db.doc('users/' + firebase.auth().currentUser.uid)
};
db.collection('products').add(data);

Obtenir une collection (produits) et toutes les références sur chaque document (détails de l'utilisateur) :

db.collection('products').get()
    .then(res => {
      vm.mainListItems = [];
      res.forEach(doc => {
        let newItem = doc.data();
        newItem.id = doc.id;
        if (newItem.userRef) {
          newItem.userRef.get()
          .then(res => { 
            newItem.userData = res.data() 
            vm.mainListItems.push(newItem);
          })
          .catch(err => console.error(err));
        } else {
          vm.mainListItems.push(newItem);  
        }

      });
    })
    .catch(err => { console.error(err) });

J'espère que cela vous aidera

4 votes

Merci pour le partage ! Je pense qu'il y a une faute de frappe dans la première ligne de Get part et que cela devrait être db.collection('products').get() . Avez-vous essayé d'obtenir l'utilisateur directement ? Je suppose que newItem.userRef.get() devrait fonctionner à la place de db.collection("users").doc(newItem.userRef.id).get()

0 votes

Merci @CRG, vous avez bien repéré la faute de frappe et vous avez bien vu qu'il faut utiliser userRef.get() à la place - c'est une façon plus simple et plus propre de le faire - merci.

87 votes

Tout d'abord, merci pour l'exemple. J'espère qu'ils ajouteront un "populate : true" à l'avenir. Sinon, la sauvegarde d'une référence est quelque peu inutile. On aurait pu faire la même chose en sauvegardant simplement le fichier uid et la référence via celui-ci.

139voto

Gil Gilbert Points 4404

Les références ressemblent beaucoup aux clés étrangères.

Les SDK actuellement disponibles ne peuvent pas stocker de références à d'autres projets. Dans un projet, les références peuvent pointer vers n'importe quel autre document dans n'importe quelle autre collection.

Vous pouvez utiliser les références dans les requêtes comme n'importe quelle autre valeur : pour filtrer, ordonner et paginer (startAt/startAfter).

Contrairement aux clés étrangères dans une base de données SQL, les références ne sont pas utiles pour effectuer des jointures dans une seule requête. Vous pouvez les utiliser pour des recherches dépendantes (qui ressemblent à des jointures), mais faites attention car chaque saut entraînera un nouvel aller-retour vers le serveur.

12 votes

Pouvez-vous nous faire part de cas d'utilisation possibles ? Est-il possible d'interroger des champs dans cette référence ? Par exemple, j'ai une friends collection listant tous mes amis ( friends/myId ). Ensuite, je fais référence à ce document dans le friends d'un autre document ( group/groupId ). J'aimerais afficher uniquement mes amis qui font partie de ce groupe, en procédant comme suit : where('friends.myId', '==', true) .

144 votes

Par ailleurs, il pourrait être utile de mettre à jour le fichier docs pour inclure un exemple d'ajout d'un type de référence.

13 votes

Je ne trouve aucune information à ce sujet ? Cela va changer toute la structure de ma base de données, j'ai besoin d'en savoir plus ...

35voto

Aswin Kumar Points 2423

Pour ceux qui recherchent une solution Javascript pour interroger par référence, le concept est le suivant : vous devez utiliser un objet "référence de document" dans la requête.

teamDbRef = db.collection('teams').doc('CnbasS9cZQ2SfvGY2r3b'); /* CnbasS9cZQ2SfvGY2r3b being the collection ID */
//
//
db.collection("squad").where('team', '==', teamDbRef).get().then((querySnapshot) => {
  //
}).catch(function(error) {
  //
});

(Bravo pour la réponse ici : https://stackoverflow.com/a/53141199/1487867 )

11voto

Pavel Shastov Points 1341

Selon le site #AskFirebase https://youtu.be/Elg2zDVIcLo?t=276 le principal cas d'utilisation pour le moment est un lien dans l'interface de la console Firebase.

1voto

Jonathan Points 63

Automatique JOINS :

DOC

expandRef<T>(obs: Observable<T>, fields: any[] = []): Observable<T> {
  return obs.pipe(
    switchMap((doc: any) => doc ? combineLatest(
      (fields.length === 0 ? Object.keys(doc).filter(
        (k: any) => {
          const p = doc[k] instanceof DocumentReference;
          if (p) fields.push(k);
          return p;
        }
      ) : fields).map((f: any) => docData<any>(doc[f]))
    ).pipe(
      map((r: any) => fields.reduce(
        (prev: any, curr: any) =>
          ({ ...prev, [curr]: r.shift() })
        , doc)
      )
    ) : of(doc))
  );
}

COLLECTION

expandRefs<T>(
  obs: Observable<T[]>,
  fields: any[] = []
): Observable<T[]> {
  return obs.pipe(
    switchMap((col: any[]) =>
      col.length !== 0 ? combineLatest(col.map((doc: any) =>
        (fields.length === 0 ? Object.keys(doc).filter(
          (k: any) => {
            const p = doc[k] instanceof DocumentReference;
            if (p) fields.push(k);
            return p;
          }
        ) : fields).map((f: any) => docData<any>(doc[f]))
      ).reduce((acc: any, val: any) => [].concat(acc, val)))
        .pipe(
          map((h: any) =>
            col.map((doc2: any) =>
              fields.reduce(
                (prev: any, curr: any) =>
                  ({ ...prev, [curr]: h.shift() })
                , doc2
              )
            )
          )
        ) : of(col)
    )
  );
}

Il suffit de placer cette fonction autour de votre observable pour qu'elle développe automatiquement tous les types de données de référence en fournissant des jointures automatiques.

Utilisation

this.posts = expandRefs(
  collectionData(
    query(
      collection(this.afs, 'posts'),
      where('published', '==', true),
      orderBy(fieldSort)
    ), { idField: 'id' }
  )
);

Note : Vous pouvez également saisir les champs que vous souhaitez développer comme deuxième argument dans un tableau.

['imageDoc', 'authorDoc']

Cela augmentera la vitesse !

Ajouter .pipe(take(1)).toPromise(); à la fin pour une version promise !

Voir aquí pour plus d'informations. Fonctionne avec Firebase 8 ou 9 !

C'est simple !

J

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