Having a hard time trying to filter out the hits in my Algolia InstantSearch searchController?

My goal is to filter out hits by schoolID. School users on my app have unique schoolIDs and I want them to be able to search through events that only they created and not see any other school’s events. I’ve been wanting to figure this out ever since I got the Algolia implemented into my app and I just can’t wrap my head around it, the concept seems so easy to explain but when i try to implement it, there is literally no change in my search results.

I copied the code that one of the Algolia team members replied with, but it still doesn’t filter out the hits by schoolID, I will attach my block of code in the updateSearchResults() method, please point out any mistakes you see in my code, I’ve been gunning to fix this big issue in my app for a while. Thanks in advance.

func updateSearchResults(for searchController: UISearchController) {
    let searchBar = searchController.searchBar
    let settings = Settings()

        .set(\.searchableAttributes, to: [.default("eventName")])
        .set(\.attributesForFaceting, to: [.filterOnly("schoolID")])
        .set(\.attributesToRetrieve, to: ["*"])

     searchResultsIndex.setSettings(settings) { (result) in
        if case .success(let response) = result {
            print("Response: \(response.wrapped)")
        }
    }
    getTheSchoolsID { (schoolID) in
        if let id = schoolID {
            let schoolID: String = id
        }
        
        let query = Query(searchBar.searchTextField.text!).set(\.filters, to: "schoolID:\(schoolID)")

        searchResultsIndex.search(query: query) { (result) in
            if case .success(let response) = result {
                print("Query Success!")
            }
        }
    }
}

Hi @dantesauder ,

The first potential source of issue is that you call the search method in parallel with applying the index settings. The configuration of your index must be done just once and not on each search query. Please make you sure you launch your search after applying your index settings. In the given example you should move your getTheSchoolsID call inside the setSettings method callback.

Then, could you check the query.filters value before calling your searchResultsIndex.search? It looks like the schoolID is an optional value, so its string interpolation will look like Optional(your_school_id) or Optional(nil). This format won’t be accepted by the engine. You have to unwrap the value before applying it to the query.

Ok i don’t get what you mean in your first paragraph, the setSettings() method gets called either way, because it’s in the updateSearchResults() method, so I don’t understand how moving the getTheSchoolsID() closure into the setSettings() will prevent the issue. And for the second paragraph I tried to unwrap the schoolID, but it wasn’t changing it’s value. I tried to print out the filter to see it what it printed out and I got this.

Here is my code currently:

func updateSearchResults(for searchController: UISearchController) {
    let searchBar = searchController.searchBar
    let settings = Settings()

        .set(\.searchableAttributes, to: [.default("eventName")])
        .set(\.attributesForFaceting, to: [.filterOnly("schoolID")])
        .set(\.attributesToRetrieve, to: ["*"])

     searchResultsIndex.setSettings(settings) { (result) in
        if case .success(let response) = result {
            print("Response: \(response.wrapped)")
        }
    }
    getTheSchoolsID { (schoolID) in
        if let id = schoolID {
            let schoolID: String! = id
        }
        
        let query = Query(searchBar.searchTextField.text!).set(\.filters, to: "schoolID:\(schoolID!)")

        searchResultsIndex.search(query: query) { (result) in
            if case .success(let response) = result {
                print("\(query.filters!)")
            }
        }
    }
}

The optional only goes away in the print statement cause of the force unwrap on .filters but when I force unwrap everything except for the print statement, it still prints out the optional value.

When you’re answering, can you possibly add a code snippet, it makes it a bit easier for me to understand. It’s already unfortunate enough that I gotta wait a week or so for a reply, let alone a reply that doesn’t fully clarify my issue, so a reply with a code snippet would really help. Thanks.

I didn’t put the code snippets as the code you provide looks right, but I’m not sure about its context. For example the type of schoolID in the getTheSchoolsID function or how many times and where the updateSearchResults() function is called. By the way, my assumption was right, the initial filters value was wrong as the schoolID variable wasn’t unwrapped.
Is the search result you get still wrong?

The first paragraph meant that all the API client methods are asynchronous, so when you call

searchResultsIndex.setSettings() { ... }
searchResultsIndex.search() { ... }

consequently, the execution order is not guaranteed, so the search() method may actually be launched before the setSettings() and so you get the unexpected result. To make sure that the index settings are applied before you launch the search, you have to call them inside the setSettings completion callback:

searchResultsIndex.setSettings(settings) { (result) in
        if case .success(let response) = result {
            // Here we are sure, that the index settings are applied, so we can search safely
            searchResultsIndex.search(query: query) { (result) in
              if case .success(let response) = result {
                print("\(query.filters!)")
              }
        }
}

I don’t think that it’s the reason of your issue, but the understanding of this concept might save you a lot of debugging time.

Yes I still get incorrect search results, I can still search events of other school ID’s. How can I unwrap the schoolID variable? The getTheSchoolsID() method was a completion function that had an optional String, and it can’t be changed from optional to force unwrapped.

Here is that function, I use it in my app for other reasons and not just the search.

func getTheSchoolsID(completion: @escaping ((String?) -> ())) {
    listener.documentListener = db.collection(Constants.Firebase.schoolUsers).whereField("userID", isEqualTo: user!.uid).addSnapshotListener(includeMetadataChanges: true) { (querySnapshot, err) in
        if let err = err {
            print("There was an error fetching the documents: \(err)")
        } else {
            self.skoolsID = querySnapshot!.documents.map { document in
                return SchoolID(schoolID: (document.get("school_id") as! String))
            }
            
            self.tableView.reloadData()
            
            let fixID = "\(self.skoolsID)"
            let substring = fixID.dropFirst(29).dropLast(3)
            let realString = String(substring)
            completion(realString)
            
            
        }
    }
}

This is Firebase and completely unrelated to Algolia but the only reason I’m showing it is so you can see where I am grabbing that getTheSchoolsID() from that I use in my extension block of code.

I don’t know how I can unwrap this and put it in the filter, I’ve put exclamation marks behind almost everything, and nothing changes.

func updateSearchResults(for searchController: UISearchController) {
    let searchBar = searchController.searchBar
    let settings = Settings()

        .set(\.searchableAttributes, to: [.default("eventName")])
        .set(\.attributesForFaceting, to: [.filterOnly("schoolID")])
        .set(\.attributesToRetrieve, to: ["*"])

     searchResultsIndex.setSettings(settings) { (result) in
        if case .success(let response) = result {
            self.getTheSchoolsID { (schoolID) in
                let query = Query(searchBar.searchTextField.text!).set(\.filters, to: "schoolID:\(schoolID!)")
                
                searchResultsIndex.search(query: query) { (result) in
                        if case .success(let response) = result {
                            print("\(query.filters!)")
                    }
                }
            }
        }
    }
}

I tried what you told me to try, but I can still see the objects with another school ID when I search. I will do whatever it takes to understand the issue, this is a must-solve for my app, I’ve been trying to figure out this issue for almost 3 weeks. I’ll try whatever, if you have any more suggestions, maybe it’s something I need to tweak in the Algolia dashboard, let me know. Thanks