地图包含字符串的 Firestore 查询

Jak*_*aky 4 android firebase google-cloud-firestore

数据结构:

houses (collection)
  name (string)
  users (map)
    90c234jc23 (map)
      percentage: 100% (string/number)
Run Code Online (Sandbox Code Playgroud)

规则:

allow read: request.auth.uid in resource.data.users;
Run Code Online (Sandbox Code Playgroud)

问题是当我尝试查询用户拥有的房屋时:

FirebaseFirestore.getInstance().collection(House.COLLECTION)
//                .whereArrayContains(House.USERS_FIELD, currentUser.getUid()) // does not work
                .whereEqualTo("users." + currentUser.getUid(), currentUser.getUid()) // does not work either
                .get()
Run Code Online (Sandbox Code Playgroud)

不返回任何结果。

Joh*_*ika 15

您可以使用orderBy查找映射包含特定键的文档。使用此示例文档:

{
  "users": {
    "bob": {},
    "sam": {},
  }
}
Run Code Online (Sandbox Code Playgroud)

.orderBy('users.bob')只会找到包含users.bob.


Luc*_*ach 7

您无法在 Firestore 中执行此类查询,因为没有“map-contains-key”运算符。但是,通过对数据结构进行轻微调整来实现这一点有非常简单的解决方法。

具体解决方案

要求:要使此解决方案起作用,每个映射值都必须在 Firestore 查询中唯一可识别,这意味着它不能是映射或数组。

如果您的案例符合列出的要求,您可以使用@Dennis Alund 的解决方案,该解决方案建议使用以下数据结构:

{
  name: "The Residence",
  users: {
    uid1: 80,
    uid2: 20
  }
}
Run Code Online (Sandbox Code Playgroud)

通用解决方案

如果您的地图值是地图或数组,您需要为每个值添加一个属性,该属性将在所有创建的此类型值中保持不变。下面是一个例子:

{
  name: "The Residence",
  users: {
    uid1: {
      exists: true,
      percentage: 80,
      ...
    },
    uid2:  {
      exists: true,
      percentage: 20,
      ...
    },
  }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以简单地使用查询:

_firestore.collection('houses').whereEqualTo('users.<uid>.exists', true)
Run Code Online (Sandbox Code Playgroud)


Den*_*und 5

此查询不起作用,因为您的users字段是地图而不是数组。

.whereArrayContains(House.USERS_FIELD, currentUser.getUid())
Run Code Online (Sandbox Code Playgroud)

这个查询

.whereEqualTo("users." + currentUser.getUid(), currentUser.getUid())

不起作用,因为您的映射值 forusers.<uid>是一个字符串,该字符串表示percentage: xx%该语句正在测试 if percentage: xx% === <uid>,这是错误的。

并且该策略将是有问题的,因为您无法进行查询以查找“非空”或“字符串非空”等的项目。

我假设百分比是用户对房子的所有权(?)。如果是这样,如果您想保持与问题中相同的文档结构,那么尝试像这样构建内部文档数据可能会更好

{
  name: "The Residence",
  users: {
    uid1: 80,
    uid2: 20
  }
}
Run Code Online (Sandbox Code Playgroud)

这将允许您进行查询,例如

.whereGreaterThan("users." + currentUser.getUid(), 0)
Run Code Online (Sandbox Code Playgroud)

查找在该房屋中拥有部分所有权的用户。

但是有一点警告,一旦您需要复合索引,您就会开始遇到维护该结构的问题。您可能要考虑存储拥有该房屋的用户数组,以便于查询。

  • 很好的解释丹尼斯。我确实会添加一个 **additional** 字段 `owners`,它只是一个所有者 UID 的数组,以便您可以在其上使用 `whereArrayContains`。 (3认同)