如何使用Firebase进行基本的自动完成/文本预览?
例如,想象一下由Firebase支持的博客,其中博主可以使用标签标记帖子。当博主正在标记新帖子时,如果他们能够看到所有当前存在的标签与他们输入的前几次击键相匹配将会很有帮助。因此,如果“博客”,“黑色”,“炽热的马鞍”和“斗牛犬”都是标签,如果用户输入“bl”,他们会获得前三个而不是“斗牛犬”。
我最初的想法是我们可以使用标记的优先级设置标记,并使用startAt,这样我们的查询看起来像:
fb.child('tags').startAt('bl').limitToFirst(5).once('value', function(snap) {
console.log(snap.val())
});
但这也会让“斗牛犬”成为结果之一(不是世界末日,也不是最好的)。使用startAt('bl')。endAt('bl')不返回任何结果。还有另一种方法可以实现这个目标吗?
(我知道有一个选择是我们可以使用搜索服务器,比如ElasticSearch,请参阅https://www.firebase.com/blog/2014-01-02-queries-part-two.html - 但我希望尽可能多地保留在Firebase中。)
修改
正如加藤所说,这是一个具体的例子。我们有20,000个用户,其名称存储如下:
/users/$userId/name
用户通常会按名称查找其他用户。当用户正在查找他们的好友时,我们想要一个下拉列表来填充名称以搜索者输入的字母开头的用户列表。因此,如果我输入“Ja”,我会期望在下拉列表中看到“Jake Heller”,“jake gyllenhaal”,“Jack Donaghy”等。
答案 0 :(得分:13)
我知道这是一个古老的话题,但它仍然是相关的。根据Neil上面的回答,您可以更轻松地搜索以下内容:
fb.child('tags').startAt(queryString).endAt(queryString + '\uf8ff').limit(5)
上面查询中使用的\ uf8ff字符是一个非常高的代码点 在Unicode范围内。因为它是在大多数常规字符之后 Unicode,查询匹配以queryString开头的所有值。
答案 1 :(得分:6)
受到Kato评论的启发 - 解决此问题的一种方法是将优先级设置为要搜索自动完成的字段,并使用startAt(),limit()和客户端过滤仅返回你想要的结果。您需要确保优先级和搜索字词较低,因为Firebase区分大小写。
这是一个粗略的例子,使用我在问题中列出的用户示例来证明这一点:
要搜索“ja”,假设所有用户的优先级都设置为用户名的小写版本:
fb.child('users').
startAt('ja'). // The user-inputted search
limitToFirst(20).
once('value', function(snap) {
for(key in snap.val()){
if(snap.val()[key].indexOf('ja') === 0) {
console.log(snap.val()[key];
}
}
});
这应该只返回实际以“ja”开头的名称(即使Firebase实际上在“ja”之后按字母顺序返回名称)。
我选择使用limitToFirst(20)来保持较小的响应大小,因为实际上,自动完成下拉列表永远不需要超过20。可能有更好的方法来进行过滤,但这至少应该证明这个概念。
希望这有助于某人! Firebase人员很可能有更好的答案。
(请注意,这是非常有限的 - 如果有人搜索姓氏,它将不会返回他们正在寻找的内容。因此,“最佳”答案可能是使用像Kato那样的搜索后端{ {3}}。)
答案 2 :(得分:4)
让我感到有一种比客户端过滤或黑客弹性更简单,更优雅的方法。
通过将搜索关键字转换为其'Unicode值并将其存储为优先级,您可以通过将值递增1来搜索startAt()和endAt()。
var start = "ABA";
var pad = "AAAAAAAAAA";
start += pad.substring(0, pad.length - start.length);
var blob = new Blob([start]);
var reader = new FileReader();
reader.onload = function(e) {
var typedArray = new Uint8Array(e.target.result);
var array = Array.prototype.slice.call(typedArray);
var priority = parseInt(array.join(""));
console.log("Priority of", start, "is:", priority);
}
reader.readAsArrayBuffer(blob);
然后,您可以将搜索优先级限制为“ABB”键,方法是将最后一个charCode递增1并进行相同的转换:
var limit = String.fromCharCode(start.charCodeAt(start.length -1) +1);
limit = start.substring(0, start.length -1) +limit;
开始时间:6566 65 65656565650000
结束:6566 66 65656565650000
Simples!
答案 3 :(得分:1)
基于Jake和Matt的回答,sdk 3.1的更新版本。 ' .limit'不再有效:
firebaseDb.ref('users')
.orderByChild('name')
.startAt(query)
.endAt(`${query}\uf8ff`)
.limitToFirst(5)
.on('child_added', (child) => {
console.log(
{
id: child.key,
name: child.val().name
}
)
})