web-dev-qa-db-fra.com

Dans Firestore, comment pouvez-vous effectuer une requête composée impliquant une clé dans une carte sans créer d'index pour chaque clé?

Dans Firestore, comment pouvez-vous effectuer une requête composée impliquant une clé dans une carte sans créer d'index pour chaque clé?

Par exemple, considérons une collection contenant des articles de blog et chaque article de blog ayant des catégories. 

Post {
    title: ..
    ...
    categories: {
        cats: true
        puppies: true
    }   
}

Pour interroger les publications d'une catégorie particulière de manière paginée, nous ferions quelque chose comme ceci:

let query = db.collection(`/posts`)
    .where(`categories.${categoryId}`, '==', true)
    .orderBy('createdAt')
    .startAfter(lastDate)
    .limit(5);

Mais il semble que cela nécessite un index composite (categories.<categoryId> et createdAt) pour chaque catégorie. Y a-t-il un moyen de contourner cela?

Dans mon cas, il n'est pas possible de créer des indices composites pour toutes les catégories, car celles-ci sont générées par l'utilisateur et peuvent facilement dépasser 200 (limite des indices composites dans Firestore).

6
RyanM

Ceci est faisable en définissant la valeur de chaque catégorie sur ce que vous voulez trier. Firestore a un guide qui couvre cela.

Post {
    title: ..
    ...
    categories: {
        cats: createdAt
        puppies: createdAt
    }   
}

let query = db.collection(`/posts`)
    .where(`categories.${categoryId}`, '>', 0)
    .orderBy(`categories.${categoryId}`)
    .startAfter(lastDate)
    .limit(5);
4
abraham

Pour autant que je sache, Firestore devrait générer automatiquement ces index. Depuis la page de documentation sur les tableaux, les listes et les ensembles :

Considérez cette structure de données alternative, où chaque catégorie est la clé d'une carte et toutes les valeurs sont vraies:

// Sample document in the 'posts' collection
{
    title: "My great post",
    categories: {
        "technology": true,
        "opinion": true,
        "cats": true
    }
}

Désormais, il est facile de rechercher tous les articles de blog dans une seule catégorie:

// Find all documents in the 'posts' collection that are
// in the 'cats' category.
db.collection('posts')
    .where('categories.cats', '==', true)
    .get()
    .then(() => {
        // ...
    });
)

Cette technique repose sur le fait que Cloud Firestore crée des index intégrés pour tous les champs de document, même les champs d'une carte imbriquée.

Bien que le côté gauche de votre condition where puisse être variable, cela ne change pas le fait que ces index doivent être générés automatiquement (pour autant que je puisse voir).

1
Frank van Puffelen

Firestore autorise maintenant l'opérateur array-contains.
Si vous souhaitez filtrer des documents contenant une valeur spécifique, essayez ceci.

Tout d’abord, changez le champ Carte en champ Array.

Post {
    title: ..
    ...
    categories: [
        cats,
        puppies
    ]
}

Deuxièmement, utilisez array-contains et orderBy pour chaque champ.

let query = db.collection(`/posts`)
    .where('categories', 'array-contains', 'cats')
    .orderBy('createdAt')
    .startAfter(lastDate)
    .limit(5);

Vous pouvez consulter le document officiel sur l'opérateur array-contains depuis ici .

0
wonsuc

Essayez de restructurer votre magasin de données. La documentation Firebase est très utile ici.

Limites de la requête

Cloud Firestore ne prend pas en charge les types de requêtes suivants:

  • Requêtes avec filtres de plage sur différents champs, comme décrit dans la section précédente.
  • Requêtes uniques sur plusieurs collections ou sous-collections. Chaque requête est exécutée sur une seule collection de documents. Pour plus des informations sur la manière dont votre structure de données affecte vos requêtes, voir Choisissez une donnée Structure .
  • Requêtes de membres individuels du groupe. Vous pouvez toutefois modéliser et interroger des données de type tableau en utilisant les techniques décrites dans Utilisation des tableaux, Listes, et Ensembles .
  • Requêtes logiques OR. Dans ce cas, vous devez créer une requête distincte pour chaque condition OR et fusionner les résultats de la requête dans votre application.
  • Requêtes avec une clause! =. Dans ce cas, vous devez scinder la requête en une requête supérieure à et une requête inférieure à. Par exemple, bien que la clause de requête où ("age", "! =", "30") n'est pas supportée, vous pouvez obtenir le même jeu de résultats en combinant deux requêtes, une avec la clause où ("âge", "<", "30") et un avec la clause où ("âge", ">", 30).
0
Ron Royston