Swift 中带有过滤器的高级 Firebase 查询
Posted
技术标签:
【中文标题】Swift 中带有过滤器的高级 Firebase 查询【英文标题】:Advanced Firebase Query with filter in Swift 【发布时间】:2016-07-10 21:59:42 【问题描述】:我刚从关系数据库学校毕业,处理 JSON 数据库对于新手来说并不是一件容易的事。我有这个结构来存储用户:
"users" :
"0CcKvNkOm5fVqL" :
"birthday" : 564688000,
"country" : "US",
"email" : "email@live.com",
"firstName" : "John",
"gender" : "male",
"isOnline" : true,
"lastLoginDate" : 1468166460486,
"lastName" : "Paul",
"learningLanguages" : [
"language" : "fr_FR",
"levelID" : 2
],
"profileImage" : "https://firebasestorage.googleapis.com/image.jpg",
"providerID" : "Firebase",
"registrationDate" : 1468168460486,
"speakingLanguages" : [
"language" : "es_ES",
"levelID" : 7
]
我在我的应用中提供了一个搜索屏幕,用户可以在其中搜索其他用户,并且他们可以组合所有这些过滤器参数:
示例:
获取10
用户starting from index 0
是谁:
male
和来自"US"
和 speaks "da_DK"
和levelID 2
或/和 "fr_FR"
和any level
和学习“de_DE”with
level 1**and/or**
learns “ar_AR”with
level 4`
和与age range between 18 and 24
和按isOnline
和 last login date
订购。
如果有一个名为 users_languages 的表,这对 SQL 来说是一项简单的任务:
SELECT ...
FROM users AS u
JOIN users_languages AS l
ON u.id = l.id
WHERE u.gender = "male"
AND u.age BETWEEN 18 AND 24 // need claculation but let's keep it simple
AND u.country = "US"
AND ((l.language = "de_DE" AND l.mode = "learning" AND l.level = 1) OR (l.language = "ar_AR" AND l.mode = "learning" AND l.level = 4))
....
ORDER BY isOnline, lastLoginDate DESC
LIMIT 0,10
我的问题:
-
如何使用 Firebase 以实际结构构建上述查询
如果无法针对我的特定用例改进数据库结构(以便能够以更好的方式处理上述查询)
【问题讨论】:
推荐阅读:NoSQL data modeling和my answer here 两件事:请将您的 Firebase 结构发布为文本,而不是图像。它使复制/粘贴到答案中变得更加容易,并且还使其可搜索。 Firebase 控制台具有导出功能。另外,您在任何给定时间都会有多少用户在线? @Jay thx,我已经用文本结构更新了我的问题,我期待作为第一步可能有数百或数十个 .. 但如果解决方案可以扩展,那就太好了,有什么建议吗? @FrankvanPuffelen 甚至阅读了文档,而您之前的回答似乎并没有为我的案例提供答案:( 并且我们将不胜感激 快照包含按正确顺序返回子项所需的信息。但简单地打印快照可能会将其转换为字典,从而丢失此排序信息。见***.com/questions/38266429/… 【参考方案1】:直截了当的答案是:您不能在 Firebase 中进行搜索。
让我提供一个文本墙的答案,希望能找到解决方案。
坦率地说: 正如弗兰克在他的现场 cmets 和链接中提到的那样,利用 ElasticSearch 等其他产品可能是一种解决方案。虽然它们确实提供了可扩展性,但它为等式增加了另一个产品。我建议进一步探索这些选项。
过滤很酷: 第二种解决方案是在代码中过滤。虽然这对于数千条记录来说是一个很好的解决方案,但它对于数万/数十万条记录是不可扩展的。但是,如果您有复杂的数据结构和有限的数据量,这是最好的解决方案。
请注意,如果 UI 的结构可以使其正常工作,那么即使有数百万条记录,您也可以在代码中进行过滤。决定一到两个主要搜索,例如性别。然后对所有女性执行查询。这将您的数据集减少了一半,并且在代码中更易于管理。您还可以进一步减少数据集 - 请参阅下一节。
改变是好的: 另一种选择是构建数据以匹配您将执行的查询类型。举个简单的例子:假设您要查询三个项目;性别国家年龄
您的 Firebase 结构将是
users
-Jyiai09jsi
data: "male_US_40"
-Jqkjisjida
date: "male_US_27"
-JyHYjlkall
data: "male_US_30"
然后查询美国所有30-40岁的男性用户
usersRef.queryOrderedByChild("data").queryStartingAtValue("male_US_30")
.queryEndingAtValue("male_US_40").observeSingleEventOfType(
.Value, withBlock: snapshot in
print(snapshot)
)
这里的好处是它具有可扩展性,但缺点是您不能只查询美国用户。另一方面,这是一个小得多的数据集,您可以在代码中进一步过滤。
重复数据是你的朋友: 好消息是也有一个解决方案:磁盘空间很便宜,所以复制你的数据
user_countries
US
-Jyiai09jsi: true
-Jqkjisjida: true
-JyHYjlkall: true
UK
etc etc
user_gender
male
-Jyiai09jsi: true
-Jqkjisjida: true
-JyHYjlkall: true
female
etc etc
user_speaks
da_UK
users
fr_FR
users
这种结构让您可以超级快速地访问数据组;国家、性别等。我在这里使用 true 作为占位符,但从技术上讲,您也可以在该位置拥有每个用户节点。但是,这将再次在查询期间读取大量数据;一堆“真正的”节点是非常少量的数据,即使有数千个节点。
SQL ftw! 其他需要考虑的是您如何使用 Firebase 的异步特性。您是否真的需要将该数据存储在 Firebase 中,或者您可以将该数据存储在另一个基于云的 SQL 服务器中以进行查询并将指向该数据的链接存储在 Firebase 中。这样您就可以通过 SQL 查询您心中的内容,然后使用 Firebase 进行消息传递、更新等。
最后的想法如果您想进行此类搜索,最好的办法是以尽可能快地减少其占用空间的方式构建数据,然后在代码中过滤其余部分。想象一下有一百万条记录,然后查询male_US_30_FR。现在你有几千条记录可以轻松加载并在代码中进一步过滤
我希望这些中的一个或组合有所帮助。
【讨论】:
感谢杰伊的另一个精彩回答! 现在,Firebase Firestore 允许使用这些高级查询选项! @Eric 太真实了! Firestore 有更强大的查询。但是,如果您仔细查看原始问题,查询包含多个字段的 OR 语句,即使在今天,这对 Firestore 来说也是具有挑战性的。另请注意如果您包含具有范围比较的过滤器,则您的第一个排序必须在同一字段中,并且问题中的排序在 isOnline 和 最后登录日期 但需要按年龄,因为这是范围参数。以上是关于Swift 中带有过滤器的高级 Firebase 查询的主要内容,如果未能解决你的问题,请参考以下文章
firebase 云功能中带有 typescript 的 firebase-admin
如何在swift ios中通过键值读取子数据或过滤firebase数据