Alex Pavliuk
Alex Pavliuk

Reputation: 46

Firebase async fuzzy search fail with crash

So Im building sort of 'fuzzy_search' tool that search with selective precision. Divide string on chunks and if some of them are similar to firebase entries it return array of suggested items. And it works perfectly fine when im providing it 100% precision, but when precision is less than 1 (which is 100%) it fails with this error, as you can see results already pushed in array, but it still executes search on array with 0 elements in it, but it shouldn't. Firebase log

And I feel like issue with async functions in my code because it's kinda a lot in it, and im not so good in it.

Anyway that's my code

export const ScreenName =  functions.https.onRequest( async (req,res) => {
//getting variables from request and checking them 
if(req.method == 'GET'){
    var name: any = req.query.name as string
    var precision: any = req.query.precision
}else if(req.method == 'POST'){
    var name: any = req.body.name as string
    var precision = req.body.precision
}
if(!name){
    res.status(400).send('Parameter "name"  was not provided')
    return
}else if (!precision || precision <  0.9 || precision > 1){
    res.status(400).send('Parameter 0.9 < "precison" < 1')
    return
}
console.log(`searching for ${name} with ${precision} precision`)

let target = '-'+name.toLowerCase().replace(' ','')+'-'
let chunks : string[] = []
for(let i = 0; i < target.length - 1; i++){
    chunks.push(target[i] + target[i+1])
}
let target_points : number = Math.floor(chunks.length * precision);
console.log('data is ready for search, ' + `string: ${target} ,elements: ${chunks} , ${chunks.length} chunks ,points: ${target_points}`)



//Function takes array of strings and  returns all combinations of given number amount of strings from this array 
// so if ['a','b','c'], 2 provided, it will return [['a','b'],['a','c'],['c','b']]
function combinations(array: string[], num: number) {
    let result: string[][] = [];

    function helper(start: number, combination: string[]) {
      if (combination.length === num) {
        result.push(combination);
        return;
      }

      for (let i = start; i < array.length; i++) {
        helper(i + 1, [...combination, array[i]]);
      }
    }
  
    helper(0, []);
    return result;
  }

let target_combinations : string[][] = combinations(chunks, target_points)
console.log('combinations created: ' + target_combinations.length)


let index = db.collection('index')
let results: FirebaseFirestore.DocumentData[] = []; 



let promises: Promise<void>[] = []

//Function takes array of combinations and data and checks for simular words  and pushes them into array
async function getResults(combs : string[], ref: FirebaseFirestore.Query<DocumentData>){
    return new Promise<void>(async (resolve) => {
        console.log(`searching ${combs}`)
        let query = ref.where(combs[0], '==', true);
        let snapshot= await query.get()
        if (snapshot.empty) {
            console.log(combs[0] + 'empty(')
            resolve()
        } 
        else{
            combs.shift()
            if(combs.length === 0){
                console.log('result found')
                results.push(snapshot.docs.map((d) => d.data()))
                console.log('result pushed')
                resolve()
            }
            console.log(combs +' ||' + combs.length )
            await getResults(combs,query)
            resolve()
        }
    })
}


console.log('exequting queries')
target_combinations.forEach(async (arr) => {
    promises.push(getResults(arr, index))
})

await Promise.all(promises)
res.status(200).send([...new Set(results)])
})

And I guess specifically this is the issue:

      async function getResults(combs : string[], ref: FirebaseFirestore.Query<DocumentData>){
return new Promise<void>(async (resolve) => {
    console.log(`searching ${combs}`)
    let query = ref.where(combs[0], '==', true);
    let snapshot= await query.get()
    if (snapshot.empty) {
        console.log(combs[0] + 'empty(')
        resolve()
    } 
    else{
        combs.shift()
        if(combs.length === 0){
            console.log('result found')
            results.push(snapshot.docs.map((d) => d.data()))
            console.log('result pushed')
            resolve()
        }
        console.log(combs +' ||' + combs.length )
        await getResults(combs,query)
        resolve()
    }
})
  }
   console.log('exequting queries')
   target_combinations.forEach(async (arr) => {
   promises.push(getResults(arr, index))
   })

   await Promise.all(promises)
   res.status(200).send([...new Set(results)])
   })

And actual entries in db looks like this Firebase fields

I tried a lot when I was building this function, such as catching errors and console logging everything to track progress

Upvotes: 1

Views: 71

Answers (0)

Related Questions