在Firestore中,如何在不为每个键创建索引的情况下执行涉及地图中的键的复合查询?

Rya*_*anM 17 javascript firebase google-cloud-firestore

在Firestore中,如何在不为每个键创建索引的情况下执行涉及地图中的键的复合查询?

例如,考虑一个包含博客帖子的集合,每个博客帖子都有类别.

Post {
    title: ..
    ...
    categories: {
        cats: true
        puppies: true
    }   
}
Run Code Online (Sandbox Code Playgroud)

为了以分页方式查询特定类别中的帖子,我们将执行以下操作:

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

但似乎这需要每个类别的综合索引(categories.<categoryId>createdAt).有没有办法解决?

就我而言,为每个类别创建复合索引是不可行的,因为类别是用户生成的,并且可能很容易超过200(Firestore中复合索引的限制).

Fra*_*len 12

据我所知,Firestore应该自动生成这些索引。在数组,列表和集合文档页面上

考虑这种替代数据结构,其中每个类别都是映射中的键,所有值均为true:

// Sample document in the 'posts' collection
{
    title: "My great post",
    categories: {
        "technology": true,
        "opinion": true,
        "cats": true
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,很容易查询单个类别中的所有博客文章:

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

此技术依赖于Cloud Firestore为所有文档字段(甚至嵌套地图中的字段)创建内置索引的事实。

尽管where条件的左侧可能是可变的,但这并不能改变这些索引应该自动生成的事实(据我所知)。

  • 嘿@Frank,谢谢你的回答。在简单的情况下,您是正确的,但是在使用“orderBy”子句时会出现问题,这是为了能够使用“startAfter”对查询进行分页所必需的。似乎只要添加“orderBy”,就需要创建复合索引,但我希望还有另一种方法 (2认同)

abr*_*ham 9

可以通过将每个类别的值设置为要排序的内容来实现。Firestore的指南对此进行了介绍。

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

let query = db.collection(`/posts`)
    .where(`categories.${categoryId}`, '>', 0)
    .orderBy(`categories.${categoryId}`)
    .startAfter(lastDate)
    .limit(5);
Run Code Online (Sandbox Code Playgroud)


won*_*suc 6

现在 Firestore 允许array-contains运营商。
如果要过滤包含特定值的文档,请尝试此操作。

首先,将 Map 字段更改为 Array 字段。

Post {
    title: ..
    ...
    categories: [
        cats,
        puppies
    ]
}
Run Code Online (Sandbox Code Playgroud)

其次,对每个不同的字段使用array-containsorderBy

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

您可以array-contains此处查看有关运营商的官方文档。