web-dev-qa-db-fra.com

Cloud Firestore: comment récupérer une référence de document dans ma requête de collection et la mapper en tant que valeur JSON?

Disons que j'ai une collection de commentaires. Chaque objet de commentaire a un "doc ref" à l'utilisateur qui a posté. J'ai besoin d'une requête qui renverra une liste de commentaires, y compris la valeur de chaque référence utilisateur, donc ma requête renvoie un joli formatage d'objets de commentaire Json.

9
Mauricio Silva

Une question similaire a été posée ici À quoi sert le type de données de référence firestore? , je ne pense pas qu'il soit possible de faire ce que vous demandez en fonction de cette réponse https: // stackoverflow .com/a/46570119/47345 .

Vous devez charger chaque référence vous-même, par exemple.

const comments = []
firebase.firestore().collection('/comments').get().then(snapshot => {
  snapshot.docs.forEach(doc => {
    const comment = doc.data()
    comment.userRef.get().then(snap => {
      comment.user = snap.data()
      comments.Push(comment)
    })
  })
})

Pour de nombreux commentaires, cela ajoutera beaucoup de frais généraux. Vous pouvez peut-être écrire une CloudFunction qui fait le travail pour vous tous côté serveur et vous renvoie un JSON formaté.

Il semble qu'ils pourraient travailler sur la prise en charge de cela à l'avenir: https://stackoverflow.com/a/46614683/47345

12
user473453

Je vous suggère de dupliquer les données utilisateur dans chaque commentaire. Créez un champ dans le document de commentaire qui est un objet nommé user et fournissez la quantité minimale d'informations requise pour afficher le commentaire. Ainsi, votre comment doc pourrait ressembler à ...

{
  id: 'CEXwQAHpk61vC0ulSdZy',
  text: 'This is a comment',
  user: {
    id: 'd5O4jTsLZHXmD1VJXwoE,
    name: 'Charlie Martin',
    avatar: 'https://...'
  }
}

Maintenant, vous avez tout ce dont vous avez besoin pour afficher le commentaire. Si quelqu'un clique sur l'auteur du commentaire, vous pouvez alors prendre l'identifiant et l'utiliser pour charger le profil complet du commentateur.

La duplication des données est désapprouvée dans les bases de données relationnelles car elles sont conçues pour gérer ces scénarios avec des clés étrangères.

Cependant, dans les bases de données NoSQL comme firestore, la duplication des données est en fait encouragée pour simplifier les requêtes et réduire la quantité de données envoyées sur le réseau.

Si vous aviez chargé le document user complet pour chaque commentaire, vous chargeriez probablement beaucoup plus d'informations sur l'utilisateur que nécessaire pour afficher le commentaire.

3
Charlie Martin

Cela m'a énervé aussi. J'ai créé un utilitaire d'aide qui peut remplir automatiquement le premier niveau.

Aide

import { get, set } from 'lodash'

const getReference = async documentReference => {
  const res = await documentReference.get()
  const data = res.data()

  if (data && documentReference.id) {
    data.uid = documentReference.id
  }

  return data
}

const hydrate = async (document, paths = []) => Promise.all(
    paths.map(async path => {
      const documentReference = get(document, path)

      if (!documentReference || !documentReference.path) {
        return console.warn(
          `Error hydrating documentReference for path "${path}": Not found or invalid reference`
        )
      }

      const result = await getReference(documentReference)
      set(document, path, result)
    })
  )
}

export { hydrate }

Exemple d'utilisation:

getUser = async uid => {
  return this.db
    .collection('users')
    .doc(uid)
    .get()
    .then(async documentSnapshot => {
      const data = documentSnapshot.data()
      await hydrate(data, ['company', 'someOtherNestedRef-2', 'someOtherNestedRef-1'])
      return data
    })
}

Limitation: cet exemple ne fonctionnera pas pour les références imbriquées profondes

0
ChrisRich

Je crée une solution pour cela, au moins travaille pour moi!

Imaginez que vous avez 2 collections: les utilisateurs et amis et les utilisateurs ont un document: User1 et Friends ont aussi un document: Friend1.

Ainsi, User1 a un champ de référence avec ce texte: Friends/Friend1.

Vous pouvez obtenir tous les utilisateurs et pour chacun, vous pouvez créer une carte comme celle-ci:

[
  {
    "User1":"Friend1"
  }
  {
    "Another User":"Another Friend"
  }
]
0
Tiago Pereira