在没有服务器端代码的 Firebase 中搜索
Posted
技术标签:
【中文标题】在没有服务器端代码的 Firebase 中搜索【英文标题】:Searching in Firebase without server side code 【发布时间】:2016-02-25 07:57:31 【问题描述】:我正在尝试从 Firebase 获取名称中包含给定字符串的所有用户。 例如,如果我有这些用户:
Devid, Andy, Bob
我想获取名称中包含“D”的所有用户,所以我希望结果如下:
Devid, Andy
这是我的 Firebase 目前的结构:
由于 Firebase 区分大小写,我创建了一个包含小写名称的属性 name_
。
使用 startAt 和 endAt 我可以获取名称以定义的字符串开头的所有用户
ref.orderByChild("name_").startAt(text).endAt(text+"\uf8ff").on('value', ...);
但这只会给我名称以给定字符串开头的用户,例如,如果文本是“D”,我会得到:
Devid
1) 目前我的查询的意思是,“给我所有 name_ 以给定字符串开头的用户”有没有办法让它意味着“给我所有用户的名字包含给定的字符串”? 编辑:否
Firebase 查询没有类似于全文搜索的功能 运营商。要完成这些,您要么必须集成一个 外部全文搜索引擎,还是搞个很精致的 自定义索引方案。 Firebase and indexing/search
2) 目前我不想拥有服务器端代码,有什么好的和有效的方式来实现自定义索引?
谢谢
【问题讨论】:
使用正则表达式? 遗憾的是 startAt/endAt 不支持正则表达式 使用正则表达式时,不需要使用 startAt/endAt... 这就是重点 你是对的,问题是我们只能使用 startAt/endAt/equalsTo 来做查询。这是文档firebase.com/docs/web/guide/… Firebase 查询没有任何类似于全文搜索运算符的功能。要完成这些,您要么必须集成一个外部全文搜索引擎,要么提出一个非常复杂的自定义索引方案。以前有人问过这个问题,所以我会找到一个重复的。 【参考方案1】:好的 - 目前的结构无法完全按照您的意愿行事。
但是这只是突然出现在我的脑海中:
users:
user_1234
first_name: "Devid"
components:
"D": true
"e": true
"v": true
"i": true
"d": true
user_5678
first_name: "Andy"
components:
"A": true
"n": true
"d": true
"y": true
user_1010
first_name: "Bob"
components:
"B": true
"o": true
"b": true
这里有一些 ObjC 代码来实现它(并且已经过测试!)
Firebase *ref = [myRootRef childByAppendingPath:@"users"];
FQuery *q1 = [ref queryOrderedByChild:@"components/b"];
FQuery *q2 = [q1 queryEqualToValue:@1];
[q2 observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot)
NSLog(@"%@", snapshot.value);
];
此代码返回 Bob。
要获取所有“d”人,请将“components/b”更改为“components/d”
编辑:
您可以非常疯狂并添加更多组合以扩展您的搜索能力
users:
user_1234
first_name: "Devid"
components:
"D": true
"e": true
"v": true
"i": true
"d": true
"De": true
"Dev": true
"Devi": true
"Devid": true
"ev": true
"evi": true
"evid": true
... etc
编写几行代码来迭代名称并写出组合非常简单。
显然,将所有名字读取到快照中,将它们转储到数组中并(在 ObjC 中)使用 NSPredicate 提取您需要的内容会更有效(如果您的数据集有限)。
【讨论】:
感谢您的回复杰!我在想类似的事情。有没有办法使用这个解决方案来搜索像“De”这样的 2 个字符? 我认为像 "devid", "evid", "vid", "id", "d" 这样的东西应该可以工作,我也在考虑这样的解决方案 "d" :“e”:“v”:“i”:“d”:真。问题是:1)这个解决方案有效吗?有没有办法告诉 Firebase 索引这些数据? (我必须研究 Firebase 中的索引是如何工作的)2)是否可以在 Firebase 查询中使用这些索引,这样我就不必将所有数据下载到客户端,而只需将搜索结果下载到客户端? 1) 效率高吗?没有真正的方法来回答这个问题。这取决于您的数据集大小、搜索频率和许多其他因素。然而,虽然在视觉上它有点凌乱,但磁盘空间很便宜,所以它不应该成为问题。 2)索引,是的。请参阅 firebase 指南和示例。当您查询时,节点(或节点)中的所有数据都将包含在快照中,因此是的,它们被下载到客户端。数据的影响和数量将再次取决于您的数据集大小。 杰伊的答案很好。我从没想过有人会认真对待我评论中的“精心设计的自定义索引方案”部分,但你肯定正朝着这个方向前进。请注意,您在此处构建的内容本质上是全文搜索引擎也将执行的操作,尽管它们使用专门的数据结构来存储搜索词。 感谢两位的帮助!我决定接受这个答案,因为它提供了一个示例,说明如何在没有服务器端代码的情况下实现文本搜索,这就是问题的目的。自定义索引实现起来很有趣,但我可能会使用处理搜索的服务器端脚本。【参考方案2】:github中的oxyzen库做到了 假设您使用一些包装的 firebase 进行插入和更新
对于索引部分基本上是功能:
-
JSON 对文档进行字符串化。
删除所有属性名称和
JSON 只保存数据(正则表达式)。
删除所有 xml 标记(因此也包括 html)和属性(记住旧指南,“数据不应在 xml 属性中”),如果存在 xml 或 html,则仅保留纯文本。
删除所有特殊字符并用空格替换(正则表达式)
用一个空格替换多个空格的所有实例(正则表达式)
拆分为空格和循环:
对于每个单词,在您的数据库中的某个索引结构中添加对文档的引用,基本上包含以单词命名的子项,而子项以“ref/inthedatabase/dockey”的转义版本命名
然后像普通的 firebase 应用程序那样插入文档
在 oxyzen 实现中,文档的后续更新实际上会读取索引并更新它,删除不再匹配的单词,并添加新单词。
随后的单词搜索可以轻松找到单词 child 中的文档。 使用 hits 实现多词搜索
【讨论】:
以上是关于在没有服务器端代码的 Firebase 中搜索的主要内容,如果未能解决你的问题,请参考以下文章
为 Android 实现 Firebase 服务器端倒数计时器?
如何在没有客户端身份验证的情况下从服务器验证 Firebase 用户?