【问题标题】:Firestore - Simple full text search solutionFirestore - 简单的全文搜索解决方案
【发布时间】:2019-10-17 11:30:44
【问题描述】:

我知道 Firestore 不支持全文搜索,它为我们提供了使用第三方服务的解决方案。但是,我找到了simple“全文搜索”的简单解决方案,我认为这可能会帮助其他不想像我一样使用第三方服务来完成如此简单任务的人。 我正在尝试搜索保存在我的 companyName 下的 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 的公司。最小搜索值是没有最后一个字符的搜索值,最大搜索值是添加了“zzzzzzzzzzzzzzzzzzzzzzzz”转换为小写的搜索值。这意味着如果您搜索 My Aw,那么最小值将是 mya,最大值将是 myawzzzzzzzzzzzzzzzzzzzzzzz

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中的最高值字符,还是有其他更体面的方法可以在不添加“zzzzzzzzzzzzz”的情况下添加到搜索值最大值?

【问题讨论】:

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


【解决方案1】:

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

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
})
})

【讨论】:

    【解决方案2】:

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

    "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);
    }); 
    

    【讨论】:

    • hmm....我没有想过这种方式但是如果用户搜索不完整的关键字怎么办让在我的例子中说如果搜索的值只是 m 那么它将返回 null。
    • 是的。这是正确的。在对象中包含部分关键字可能没有意义,但您可以。根据您的要求,您还可以包含拼写错误。
    • 我喜欢这个想法...我认为这对于简单的文本搜索来说太复杂了,但是你给了我一个重要的线索,让我在我的项目中也需要完成另一个复杂的搜索。谢谢
    • 我越想你的想法,我就越喜欢它。因此,我对搜索进行了一些修改。但是想法是一样的,我相信可以修改它以进行更复杂和自定义的搜索
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 2011-01-11
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多