【问题标题】:Firestore query where map contains string地图包含字符串的 Firestore 查询
【发布时间】:2019-01-03 07:38:40
【问题描述】:

数据结构:

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

不返回任何结果。

【问题讨论】:

  • 这真的是 Firestore 数据库吗?我在文档中找不到 whereArrayContains 和 whereEqualTo。如果它不是 firestore,那么也许应该删除 google-cloud-firestore 标签。并且可能会添加实际的技术标签(实时?)。

标签: android firebase google-cloud-firestore


【解决方案1】:

您无法在 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)

编辑:

正如@Johnny Oshika 正确指出的那样,您也可以使用orderBy() 按字段名称进行过滤。

【讨论】:

  • 我如何在 Android 中做到这一点? stackoverflow.com/questions/69494502/…
  • @AndroidGeek 数据结构是一样的。该查询可能与 Android 库的语法略有不同,但查询中的过滤条件仍然为“exists 等于 true
  • 第一个语句:You cannot perform this type of query in firestore as there is no 'map-contains-key' operator 不正确。请参阅下面的解决方案,了解如何执行此操作。
【解决方案2】:

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

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

这个查询

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

不起作用,因为您的 users.&lt;uid&gt; 的映射值是一个显示 percentage: xx% 的字符串,并且该语句正在测试 percentage: xx% === &lt;uid&gt; 是否为假。

而且该策略会出现问题,因为您无法通过查询来查找“不为空”或“字符串不为空”等的项目。

我假设百分比是用户在房屋中的所有权 (?)。如果是这样,如果您想保持与您的问题中相同的文档结构,您可能会更幸运地尝试像这样构建您的房屋文档数据

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

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

.whereGreaterThan("users." + currentUser.getUid(), 0)

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

但请注意,一旦您需要composite indexes,您就会开始遇到维护该结构的问题。相反,您可能想要考虑存储拥有该房屋的用户数组,以便于查询。

【讨论】:

  • 很好的解释丹尼斯。我确实会添加一个 additional 字段 owners,它只是所有者 UID 的数组,以便您可以在其上使用 whereArrayContains
  • 嗨。不错的答案。 “一旦你需要复合索引,你就会开始遇到问题”部分仍然正确吗?也许有类似“map-contains”或“map-contains-key”索引(类型)(类似于数组包含)?现在可用还是正在开发中?谢谢。
  • @Frank :所以这个辅助数组将模拟一个幻想的“map-contains-key”
  • 是的,差不多就是这样。 Firestore 为完整字段创建索引,而不是为部分字段创建索引。因此,owners 字段提取了您要查询的字段部分。
  • RE“一旦你需要复合索引,你就会开始遇到问题”,为什么会这样?
【解决方案3】:

您可以使用orderBy 查找 map 包含某个键的文档。使用此示例文档:

{
  "users": {
    "bob": {},
    "sam": {},
  }
}

.orderBy('users.bob') 只会查找包含users.bob 的文档。

【讨论】:

    猜你喜欢
    • 2011-05-14
    • 2011-02-05
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多