如何在 Firebase 数据库中的字符串中进行简单搜索?

Posted

技术标签:

【中文标题】如何在 Firebase 数据库中的字符串中进行简单搜索?【英文标题】:How to do a simple search in string in Firebase database? 【发布时间】:2016-12-01 19:37:48 【问题描述】:

我想在我的应用程序中创建一个简单的搜索,但在互联网上找不到任何关于它的信息,这比 2014 年更新。必须有更好的方法。有 startAt 和 endAt 函数,但它们不能按预期工作并且区分大小写。你们如何解决这个问题? 2016年怎么还没有这个功能?

【问题讨论】:

这个问题是 4 年前提出的,仍在等待 firebase 添加完整的搜索功能。 【参考方案1】:

就我而言,我能够通过以下方式部分实现 SQL LIKE:

databaseReference.orderByChild('_searchLastName')
                 .startAt(queryText)
                 .endAt(queryText+"\uf8ff")

查询中使用的字符\uf8ff 是Unicode 范围内的一个非常高的代码点(它是专用使用区[PUA] 代码)。因为它位于 Unicode 中的大多数常规字符之后,所以查询匹配所有以 queryText 开头的值。 这样,通过“Fre”搜索,我可以从数据库中获取 _searchLastName 属性中具有“Fred, Freddy, Frey”作为值的记录。

【讨论】:

我怎样才能得到结果 Fred, Freddy, Frey 与搜索键:re 那是不可能的。上面的解决方案提供了“Starts With”功能,但它不允许像在 SQL Server 中那样进行全文搜索。如果您需要全文功能,那么您必须使用弹性搜索实现解决方案。 这很好用,至少对于起始字符串。但是在字符串中搜索仍然是 firebase 的一个基本问题。我觉得在 firebase 核心本身应用基于正则表达式的搜索并通过数据库参考接口公开功能应该不是什么大问题。 startAt() 还不够吗?文档说startAt() 返回值大于或等于给定值的所有节点。 endAt()在这里的作用是什么? 这里正式记录:firebase.google.com/docs/database/rest/…【参考方案2】:

创建两个字符串变量

    searchInputToLower = inputText.getText().toString().toLowerCase();

    searchInputTOUpper = inputText.getText().toString().toUpperCase();

然后在查询中设置为:

    DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Products");//Your firebase node you want to search inside..

    FirebaseRecyclerOptions<Products> options =
            new FirebaseRecyclerOptions.Builder<Products>()//the Products is a class that get and set Strings from Firebase Database.
            .setQuery(reference.orderByChild("name").startAt(searchInputUpper).endAt(searchInputLower + "\uf8ff"),Products.class)
            .build();

“名称”是产品主节点内的节点。

.startAt(searchInputUpper) & .endAt(searchInputLower + "\uf8ff") 包含您在 inputText.getText() 中输入的所有字符。

【讨论】:

【参考方案3】:

Firebase 是 noSQL,因此它不像 SQL 那样内置搜索功能。您可以按值/键排序,也可以等于

https://firebase.google.com/docs/database/android/retrieve-data

您可以在上面的链接中找到示例。那是 firebase 的最新文档。

如果您正在寻找类似 SQL 的搜索。然后看一下弹性搜索。但这会增加复杂性,因为您需要一个平台来放置它。为此,我可以推荐 Heroku 或者 GoogleCloudServers

这是一篇关于使用弹性搜索进行高级搜索的博文 https://firebase.googleblog.com/2014/01/queries-part-2-advanced-searches-with.html

【讨论】:

这很可悲,但弹性看起来是唯一的答案。谢谢你。无论如何,我都使用我的服务器进行订阅验证。【参考方案4】:

这个问题可能很老,但是有一个文档化的方式来说明如何实现这种方式,实现起来很简单。 Quoted:

要启用对 Cloud Firestore 数据的全文搜索,请使用 Algolia 等第三方搜索服务。考虑一个笔记应用程序,其中每个笔记都是一个文档:

Algolia 将成为您的firebase functions 的一部分,并将执行您想要的所有搜索。

// Update the search index every time a blog post is written.
exports.onNoteCreated = functions.firestore.document('notes/noteId').onCreate(event => 
      // Get the note document
      const note = event.data.data();

      // Add an 'objectID' field which Algolia requires
      note.objectID = event.params.noteId;

      // Write to the algolia index
      const index = client.initIndex(ALGOLIA_INDEX_NAME);
      return index.saveObject(note);
);

要实现搜索,最好的方法是使用instant search - android


示例搜索图片:GIF

【讨论】:

@PabloAlbaladejo android 代码证明你不能进行完整的字符串搜索,除非你实现我的代码 @PabloAlbaladejo 它的火力基地功能,这是他唯一能与他的问题相关的实现,因此我的回答 您的报价是指firestore“全文搜索”,而不是firebase实时数据库(存在巨大差异,您的答案混合了数据库和云函数,因此显然是题外话)。 firebase 没有此类查询的选项;你可以阅读官方firebase博客firebase.googleblog.com/2014/01/… 即时搜索是否直接与 Firebase 交互?我对云功能如何与即时搜索接口有点困惑.....【参考方案5】:

我的案例用过:

var query = 'text'
databaseReference.orderByChild('search_name')
             .startAt(`%$query%`)
             .endAt(query+"\uf8ff")
             .once("value")

通过这种方式,通过“test”搜索,我可以从数据库中的“search”属性中获取“Test 1, Contest, One test”作为值的记录。

【讨论】:

startAtendAt 在“测试,测试,测试,竞赛,一个测试”的实例中,如果我搜索 t,返回将是测试,测试和测试【参考方案6】:

您正在寻找的功能称为全文搜索,这是大多数数据库(包括 Firebase)不提供开箱即用的功能,因为它需要以针对文本优化的格式存储数据搜索(相对于过滤优化)——这是两个不同的问题集,具有不同的权衡。

因此,您必须将单独的全文搜索引擎与 Firebase 结合使用才能做到这一点,尤其是在您需要分面、错字容忍、推销等功能时。

全文搜索引擎有几种选择:

Algolia 易于启动和运行,但很快就会变得昂贵 ElasticSearch 的学习曲线陡峭但非常灵活 Typesense 旨在成为 Algolia 的开源替代品。

【讨论】:

【参考方案7】:

我终于明白了,你可以使用 where 子句来得到类似 SQL 的结果 LIKE关键字like%%like 语法:

Firestore.collection(collectionName).orderBy(field).where(field, ">=", keyword.toUpperCase()).where(field, "<=", keyword.toUpperCase() + "\uf8ff").get() 

【讨论】:

在我尝试过的所有解决方案中,这是唯一一个在 Python 中对我有用的解决方案!非常感谢!【参考方案8】:

我不知道这种方法的确定性,但在 android 上使用 firebase 版本 10.2.6,我可以做这样的事情:

firebaseDatabase.getReference("parent")
                            .orderByChild("childNode")
                            .startAt("[a-zA-Z0-9]*")
                            .endAt(searchString)

有时候效果不错

【讨论】:

是的,我想。我认为它仍然有效,因为我使用的是 firebase 版本 10.0.1 假设我有一个字符串“Apple smart phone”并且我的搜索词很聪明,它会根据上面的查询返回“Apple smart phone”吗? 不完全是,您可能需要不同的正则表达式,例如:[a-zA-Z]*[ ][a-zA-Z] Firebase 的查询方法不计算正则表达式。上述内容仅在 childNode literally 匹配 [a-zA-Z0-9]* 时匹配,而不是在它以任意数量的字母数字字符开头时匹配。【参考方案9】:

终于加入 SO 只是为了回答这个问题。 对于来自/为 python firestore.client 来到这里的任何人,这里有一个似乎对我有用的解决方案。 它基于公认答案的概念,但通过客户端而不是 db.reference() 并与来自 user12750908 的 answer 混合。

from firebase_admin import firestore 
users = db.collection("users")\
        .order_by("last_name")\
        .where("last_name", ">=", last_name.upper())\
        .where("last_name", "<=", last_name.lower() + "\uf8ff")\
        .stream()

它适用于我所做的简单测试,但如果我稍后有问题,我会更新我的答案。提醒一下,这类似于

LIKE search%

而不是

LIKE %search%.

编辑 1 我没有看到该问题的任何标签,但 title 属性提到了 Android,因此这可能不一定直接回答问题,但如果您有 python API,这应该可以工作。不幸的是,我不确定 Android 版本中是否有等效的客户端/数据库分离,就像 Python 的 Firebase Admin 中的那样。我不想删除答案,因为在搜索类似答案的过程中我没有看到任何 Firestore 客户端的答案,并希望它可以帮助其他遇到问题的人。

编辑 2020 年 9 月 3 日 这似乎在部分时间内有效。大多数时候我似乎没有问题,但是当我将它应用到另一个项目时,我得到了意想不到的结果。长话短说,您可能需要复制保存要比较的数据的方式。例如,您可能需要有一个字段将 last_name 保存为全部大写,而另一个字段将其保存为全部小写,然后将第一个 where 子句更改为比较 last_name_upper 并将第二个子句更改为比较 last_name_lowercase。到目前为止,在我的第二个项目中,这似乎产生了更准确的结果,因此如果之前的答案效果不佳,您可能想尝试一下

2020 年 9 月 7 日编辑 2020 年 9 月 3 日之前的编辑部分准确。在我匆忙思考的过程中,我完全解决了它,我完全忘记了 firebase 不允许您在不同领域使用 、=。您可能需要执行两个查询并将它们合并,但您可能仍会阅读比您真正想要的更多的文档。使用适当的搜索词与高版本或低版本进行比较似乎给出了原始答案所期望的原始结果。例如:

.orderBy("last_name_upper")
    .where("last_name_upper", ">=", this.searchForm.text.toUpperCase())
    .where("last_name_upper", "<=", this.searchForm.text.toUpperCase() + "\uf8ff")

【讨论】:

以上是关于如何在 Firebase 数据库中的字符串中进行简单搜索?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 GeoFire 坐标与 Firebase 数据库中的其他项目一起保存?

如何根据密钥对 Firebase 控制台中的节点进行排序

如何根据 android 中的用户位置从 Firebase 数据库中检索数据?

如何使用 Firebase 数据库中存储的 url 作为 UIImageView 中的图像

如何在 Android Studio 中使用 Kotlin 从 Firebase 中的数据库中获取特定值?

如何分离 Firebase 数据库中的测试和生产数据?