Firestore:如何设计数据模型以使查询数组中不存在的文档成为可能?

Fre*_*tic 5 database-design firebase google-cloud-firestore

我正在尝试找到一种方法来使用 Firestore 正确设计我的数据模型。我正在寻找类似于 Tinder 的功能,根据您的位置向您显示尚未刷卡的人。

所以我最终得到了类似的东西:

  • User1 有一系列“见过的人”
  • “尚未见过用户”/ User2 他也是具有相同文档模型的用户
  • 它们都属于同一个“Users”集合
  • 我想查询这个User1还没有刷卡的所有用户

我知道您不能执行“array_not_contains”或“!=”之类的操作,因为您查询的所有字段都需要建立索引。

所以我想知道,是否可以对数据进行建模以使其工作,或者唯一的解决方案是放弃 Firebase,因为这种查询根本不可能?

一种替代方法是将所有用户之间的所有关系(及其状态)存储在集合中。但这也意味着,每当用户注册时,我都必须创建与用户数量一样多的文档,这真的很丑陋,并且制作了大量的文档。

编辑:

再次感谢您的答复,并对我迟到的答复表示歉意。

无需创建新的数据库调用,因为您首先已经获得了该区域的所有用户。

不 如果有一个很大的响应集,我会限制一个数字。(下例中为 5)。即使我不限制数量,在下一个数据库调用中,我如何知道已添加新人员以及如何仅检索这些人员。
如果它们可以向其他用户显示,我不会将它们从用户集合中删除。

PS:我忘记了Users Collection图片中的User4。

初始数据库状态

对于用户 1,获取 5 个首个匹配项,删除现有匹配项,显示用户 5。
对于 User2,获取 5 个第一个匹配项,删除现有的匹配项,显示 User4、User5。
用户选择后,用户将被添加到他们的列表中。用户集合保持不变。

第2步

对于用户 1,获取 5 个第一个匹配项,删除现有匹配项,即使我有用户 6、7,也没有任何内容可显示。
为了解决这个问题,我启动了第二个查询,获取新的匹配项,但是,用户使用应用程序的次数越多,我的查询就越多可能需要尝试向他显示他所在区域的现有用户。

也许我误解了您所说的“初始列表”,对我来说,它是从包含所有用户(有限制)的数据库中检索的列表对象。

编辑2:

你可以查看Alex Mamo的回答了解如何查询数组中不存在的文档。

让我解释一下我的用例以及为什么我认为这行不通。

我希望能够搜索我旁边的所有用户,为了尝试在 Firebase 中执行此操作,我存储了 Geopoint。Geopoint 目前无法真正与 Firebase 一起使用,因此我在云功能中使用 Geofirestore。
我根据用户的位置存储和更新用户的地理点,因此这意味着用户位置随时间变化。我限制了此函数返回的用户数量。

初始搜索

在我的初始状态下,我检索我旁边的用户(用户 1),得到 3 和 4。
假设我存储了最后检查的用户 ID,以便稍后将其用作查询的游标(用户 4)。

现在我的地理位置发生了变化,该区域的用户也发生了变化。我请求我旁边的下一批用户,并使用我之前的 userId/document 来“startAfter”(更多信息请参见此处
,请参见下图,这是行不通的。

第二次搜索

如果我使用光标(User4),我将采用 5,但不是 2,因为在返回列表中,如果我按 Id 排序,2 将在 4 之前。
更糟糕的是,如下所示,如果返回列表甚至可能没有用户 4 在其中,光标将毫无意义。

第三搜索

我的示例有点简化,没有考虑第一个答案和我的第一次编辑中描述的内容(用户的有限子集,数据设计)。

Ale*_*amo 6

您的应用程序可能的数据库结构可能是:

\n\n
Firestore-root\n    |\n    --- users (collection)\n         |\n         --- uid (document)\n              |\n              --- acceptedUsers: ["uidOne", "uidTwo"]\n              |\n              --- declinedUsers: ["uidThree", "uidFour"]\n              |\n              --- //Other user properties\n
Run Code Online (Sandbox Code Playgroud)\n\n

机制很简单。当您第一次想要向当前(经过身份验证的)用户显示用户配置文件时,您必须创建一个将返回所有用户(在用户区域中)的查询。根据用户决定,需要在数组acceptedUsersdeclinedUsers数组中添加相应的uid。一旦您想要显示其他用户,请使用相同的查询,但这一次,您需要进行额外的操作。查询返回用户位置内的用户后,将所有这些用户添加到列表中。将来自数据库的列表与外部阵列进行比较,并从两个阵列中删除所有用户。通过这种方式,您将获得一个仅包含实际用户未看到的用户的列表。需要执行这一额外步骤来确保用户的 ID 不存在于这些数组之一中。最后,只需从列表中随机选择一个用户并向该用户显示详细信息即可。就是这样!

\n\n
\n

一种替代方法是将所有用户之间的所有关系(及其状态)存储在集合中。但这也意味着,每当用户注册时,我都必须创建与用户数量一样多的文档......这真的很难看,并且会创建大量文档。

\n
\n\n

这不是一个选择。这意味着每次用户加入您的应用程序时您都需要写入大量数据,这将是非常昂贵的。由于 Firestore 中的所有内容都与读取和写入的数量有关,因此我认为您应该再次考虑这种方法。请参阅Firestore 的使用和限制

\n\n

编辑:

\n\n

让我们考虑具有 10 条记录的初始用户列表。换句话说,该区域内的所有用户都是 10 个。您说已经看到 7 个用户,这使得列表仅包含剩余的 3 个用户。

\n\n
\n

所以我显示了 3(或者我再次请求获取更多),他检查了 3。

\n
\n\n

是的,您应该显示这 3 个用户,然后将它们从初始列表中一一删除。无需创建新的数据库调用,因为您首先已经获得了该区域的所有用户。一旦列表保持为空,您应该向用户显示一条消息,表明该特定区域中没有更多用户可以滑动。

\n\n
\n

什么时候会创建另一个数据库调用?

\n
\n\n

仅在需要时。这意味着一旦新用户进入该区域,您就会创建另一个呼叫。假设有 3 个新用户,您现在会得到 3 个用户的列表,并使用相同的算法。

\n\n
\n

我的用户越多地使用该应用程序,就越难向人们展示他没有见过的\xe2\x80\x99,因为他的列表变得更大。

\n
\n\n

如果您认为数组的增长将超出文档的容纳范围,那么您应该考虑将用户存储在集合中而不是数组中。所以在这种情况下,问题是文档有限制。因此,当您可以在文档中放入多少数据时,存在一些限制。根据有关使用和限制的官方文档:

\n\n
\n

文档的最大大小:1 MiB(1,048,576 字节)

\n
\n\n

如您所见,单个文档中的数据总量限制为 1 MiB。当我们谈论存储文本(uid)时,您可以存储相当多的内容,但随着数组变得越来越大,请注意此限制。

\n\n

但如果你能保持在这个限制之内(我个人认为你会这么做),那么你就没有什么可担心的。

\n\n

编辑2:

\n\n
\n

不 如果有一个很大的响应集,我会限制一个数字。(下例中为 5)。即使我不限制数量,在下一个数据库调用中,我如何知道已添加新人员以及如何仅检索这些人员。\n 如果可以显示它们,我不会将它们从用户集合中删除给其他用户。

\n
\n\n

如果您有大量数据(单个区域中有许多用户),是的,限制结果是个好主意,但更好的主意是以较小的块加载数据。简而言之,获取 5 个用户,一一删除,直到列表中的用户为零,加载其他 5 个用户,依此类推。这可以使用我在以下帖子中的回答来实现:

\n\n\n\n

初始列表是您第一次查询数据库时获得的列表。在本例中,初始列表将包含 5 个用户。

\n