在地图包含字符串的Firestore查询

时间:2019-01-03 07:38:41

标签: android firebase google-cloud-firestore

数据结构:

houses (collection)
  name (string)
  users (map)
    90c234jc23 (map)
      percentage: 100% (string/number)

规则:

allow read: request.auth.uid in resource.data.users;

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

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()

没有结果返回。

2 个答案:

答案 0 :(得分:4)

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

特定解决方案

要求:要使此解决方案生效,每个地图值必须在Firestore查询中唯一标识,这意味着它不能是地图或数组。

如果您的案件符合所列要求,则可以使用@Dennis Alund's solution,它建议使用以下数据结构:

{
  name: "The Residence",
  users: {
    uid1: 80,
    uid2: 20
  }
}

常规解决方案

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

{
  name: "The Residence",
  users: {
    uid1: {
      exists: true,
      percentage: 80,
      ...
    },
    uid2:  {
      exists: true,
      percentage: 20,
      ...
    },
  }
}

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

_firestore.collection('houses').whereEqualTo('users.<uid>.exists', true)

答案 1 :(得分:1)

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

.whereArrayContains(House.USERS_FIELD, currentUser.getUid())

此查询

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

不起作用,因为您的users.<uid>的映射值是一个字符串,内容为percentage: xx%,并且该语句正在测试percentage: xx% === <uid>是否为假。

由于您无法通过查询来查找“不为空”或“字符串不为空”等内容,因此该策略会出现问题。

我假设百分比是用户在房屋(?)中的所有权。如果是这样,如果您希望保持与问题中相同的文档结构,那么最好尝试像这样构建房屋文档数据

{
  name: "The Residence",
  users: {
    uid1: 80,
    uid2: 20
  }
}

这将使您可以进行

之类的查询
.whereGreaterThan("users." + currentUser.getUid(), 0)

查找在那所房子中拥有部分所有权的用户。

但是有一点警告,一旦您需要composite indexes,就会在维护该结构时遇到问题。您可能想考虑存储拥有该房屋的一系列用户,以便于查询。