在Swift中使用filter的高级Firebase查询

我刚刚来自关系数据库学校,处理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 } ] } } } 

我在我的应用程序中提供了一个搜索屏幕,用户可以搜索其他用户,他们可以组合所有这些filter参数:

例:

starting from index 0获得10用户:

  • male
  • 来自"US"
  • 并且使用levelID 2 或/和 "fr_FR"any level speaks "da_DK"
  • 并且学习“de_DE”级别1 **and/or**学习“ar_AR”级别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 

我的问题:

  1. 如何使用Firebase和实际结构构建上面的查询
  2. 如果不可能如何改进我的特定用例的数据库结构(以更好的方式处理上面的查询)

最重要的答案是:你不能在Firebase中搜索这种类型。

让我提出一个墙上的答案,希望能够找到解决方案。

坦白说:正如弗兰克在他的论点和链接中所提到的,利用ElasticSearch等其他产品可以成为一种解决方案。 虽然它们确实提供了可扩展性,但它增加了另一种产品。 我建议进一步探讨这些选择。

过滤很酷:第二种解决方案是过滤代码。 虽然这对于成千上万条记录来说是一个很好的解决方案,但它不能扩展到数十/数十万条记录。 但是,如果您具有复杂的数据结构和有限的数据量,这是最佳解决方案。

在这方面,如果UI的结构使其工作,您甚至可以使用数百万条记录来过滤代码。 确定一到两个主要搜索,例如性别。 然后对所有女性执行查询。 这会将您的数据集减少一半,并且在代码中更易于管理。 您还可以进一步减少数据集 – 请参阅下一节。

变化很好:另一个选择是构建数据以匹配您将要执行的查询类型。 举个简单的例子:假设您有三个要查询的项目; gender_country_age

您的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。 现在,您有几千条记录可以轻松加载并在代码中进一步过滤

我希望这些中的一个或组合有所帮助。