Firestore-简单的全文本搜索解决方案

时间:2019-05-31 20:35:45

标签: reactjs google-cloud-firestore google-cloud-functions

我知道firestore不支持全文搜索,它为我们提供了使用第三方服务的解决方案。但是,我找到了简单“全文搜索”的简单解决方案,并且我认为这可能对其他不想使用像我这样的第三方服务的人有所帮助。 我正在尝试搜索公司名称,该公司名称保存在Firestore集合中的公司名称下,该公司名称可以是任何格式,例如“ My Awesome Company”。当添加带有companyName的新公司或更新companyName中的值时,我还将同时保存与该公司名称相同值但小写且无空格的searchName

searchName: removeSpace(companyName).toLowerCase() 

removeSpace是我的简单自定义函数,可删除文本中的所有空格

export const removeSpace = (string) => {
    return string.replace(/\s/g, '');
}

这会将我们的公司名称更改为 myawesomecompany ,该名称保存在searchName中

现在我有一个firestore函数来搜索通过searchName索引并返回companyName的公司。最小搜索值是不带最后一个字符的搜索值,最大搜索值是将“ zzzzzzzzzzzzzzzzzzzzzzzzzzzz”添加为小写形式的搜索值。这意味着如果您搜索我的Aw ,则最小值将为 mya ,最大值将为 myawzzzzzzzzzzzzzzzzzzzzzzzzzzz

exports.handler = ((data) => {
const searchValue = data.value.replace(/\s/g, '').toLowerCase()
const minName = searchValue.substr(0, searchName.length-1)
const maxName = searchValue + "zzzzzzzzzzzzzzzzzzzzzzzz"
let list = []
const newRef = db.collection("user").where("profile.searchName", ">=", minName).where("profile.searchName", "<=", maxName)
return newRef.get()
.then(querySnapshot => {
    querySnapshot.forEach(doc => {
        list.push({ name: doc.data().profile.companyName})
    })
    return list
})
})

我没有时间对其进行全面测试,但是到目前为止,它没有任何问题。如果发现任何问题,请告诉我。现在的问题是

“ z”字符是Firestore中的最高值字符,还是还有其他更体面的方式可以在不添加“ zzzzzzzzzzzzzzz”的情况下添加到搜索值最大值中?

2 个答案:

答案 0 :(得分:0)

我喜欢您对文本进行预处理以便可以查询的决定,但是您可以通过与用户存储小写关键字并进行搜索来提供更灵活的搜索。换句话说,转换:

"My Awesome Company"

到...

{ my: true, awesome: true, company: true }

...并对此进行测试。

添加/更新属性时:

// save keywords on the user
let keywords = {}
companyName.split(' ').forEach(word => keywords[word.toLowerCase()] = true)

查询时:

let searchKeywords = userInputString.split(' ').map(word => word.toLowerCase())

let collection = db.collection("user")
searchKeywords.forEach(keyword => { 
  collection = collection.where(`keywords.${keyword}` , '==' , true);
}); 

答案 1 :(得分:0)

对先前的答案做了一些修改,我进行了另一个简单的文本搜索。我将关键字保存到数组中,而不是将其保存在这样的对象中

nameIndex: textIndexToArray(companyName)

其中textIndexToArray是我的自定义函数

export const textIndexToArray = (str) => {
const string = str.trim().replace(/ +(?= )/g,'')
let arr = []
for (let i = 0; i < string.trim().length; i++) {
    arr.push(string.substr(0,i+1).toLowerCase());
}
return arr
}

将文本转换为数组。例如

"My Company"

将返回

[m, my, my , my c, my co, my com, my comp, my compa, my compan, my company]

将nameIndex保存在Firestore中,我们可以简单地通过nameIndex查询数据并返回companyName

exports.handler = ((data) => {
const searchValue = data.value.toLowerCase()
let list = []
const newRef = db.collection("user").where("nameIndex", "array-contains", searchValue)
return newRef.get()
.then(querySnapshot => {
    querySnapshot.forEach(doc => {
        list.push({ name: doc.data().companyName, })
    })
    return list
})
})