使用映射字段降低索引费用

本页面介绍如何使用映射字段来管理一组子字段的索引设置。

最佳做法是移除未使用的索引,以减少存储费用并提升写入性能。默认情况下,Firestore 会为文档中的每个字段构建一个单字段索引。您可以通过定义索引例外项来控制单字段索引,但每个数据库最多只能有 200 个单字段索引例外项。在停用所有未使用的单字段索引之前,可能会达到此上限。

您可以将具有相同索引要求的文档字段分组到一个映射字段下,从而避免达到例外项上限。然后,您可以向该映射字段应用索引例外项,这一例外项也会应用于映射字段的子字段。

解决方案:使用映射字段帮助管理索引

假设某个应用依赖于一组 game_event 文档。请考虑以下两种数据模型:

顶级文档字段

Node.js
db.collection('game_events').doc().set({
   timestamp: Firestore.FieldValue.serverTimestamp(),
   user_id: 'huDIl8H88kFAFAdcHayf',
   team_id: '6Q5BhBESeTPk8LT0O59I',
   event_type: 'rare_item_drop',
   display_text: 'You found a rare item!',
});

映射字段和子字段

在此数据模型中,所有文档字段都成为 details 字段的子字段:

Node.js
db.collection('game_events').doc().set({
  details: {
    timestamp: Firestore.FieldValue.serverTimestamp(),
    user_id: 'huDIl8H88kFAFAdcHayf',
    team_id: '6Q5BhBESeTPk8LT0O59I',
    event_type: 'rare_item_drop',
    display_text: 'You found a rare item!',
  }
});

假设此应用始终根据 user_idtimestamp 或者 team_idtimestamp 查询 game_event 文档。例如:

Node.js
let query_user_events = db.collection('game_events')
                          .where('details.user_id', '==', 'huDIl8H88kFAFAdcHayf')
                          .orderBy('details.timestamp');

let query_team_events = db.collection('game_events')
                          .where('details.team_id', '==', '6Q5BhBESeTPk8LT0O59I')
                          .orderBy('details.timestamp');

请注意有关此应用的以下事项:

  • 应用依赖于 details.user_id, timestampdetails.team_id, timestamp 的复合索引。
  • 应用不使用 timestampuser_idteam_idevent_typedisplay_text 的单字段索引。

基于这些索引要求,最好是停用 timestampuser_idteam_idevent_typedisplay_text 的单字段索引。现在来比较一下这两个数据模型所需的例外项。

停用顶级字段的索引

要停用顶级字段数据模型中的单字段索引,您必须为每个字段定义一个例外项。您的例外项数量增加了五个,您每向数据模型添加一个新字段,都必须再定义一个例外项来停用其单字段索引。

停用子字段的索引

要停用映射字段和子字段数据模型的单字段索引,您可以为映射字段定义一个例外项。映射字段的例外项会将同样的索引设置应用于该映射字段的子字段。如果您为 details 字段添加一个新的子字段,则例外项会自动停用新子字段的单字段索引。

例如,使用 Firebase CLI 为 firestore.indexes.json 文件添加相应的索引例外项后,系统会停用 game_events 集合的单字段索引:

{
    "collectionGroup": "game_events",
    "fieldPath": "details",
    "indexes": []
},

如果您以后需要某个子字段的单字段索引,则可以使用例外项覆盖映射字段的索引设置。子字段的例外项会覆盖该子字段继承的索引设置。例如:

{
    "collectionGroup": "game_events",
    "fieldPath": "details.event_type",
    "indexes": [
      {
        "order": "ASCENDING",
        "queryScope": "COLLECTION"
      },
    ]
},

何时使用此方法

在上面的示例中,映射字段和子字段方法将例外项数量从 5 个减为 1 个。假设有一个类似的文档数据模型,其中包含 200 个字段。那么此方法可将例外项数量从 200 个减少到 1 个。

如果文档数据模型包含多个带有未使用单字段索引的字段,您应该考虑使用映射字段和子字段方法。对于包含许多字段的文档,尤其应该考虑这种方法。