Swift - InstantSearch - Fetch last added search results

Hello algolia community,

merry christmas to all of you. All the best for you and for your families.

I have an issue with fetching the latest search result that is added to an index. Basically, I just want to refresh the same search query manually to receive the last added results. This can be either one new result or multiple ones.

I observed one thing. After I was sure that a new search result was added, I refreshed my collection view to get the updated entries in the index.

In the numberOfItemsInSection delegate method, I printed out the number of hits:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    print(hitsSource?.numberOfHits())
... }

First, I received the updated number like it is supposed to be:

2020-12-24T13:42:41+0100 info com.algolia.InstantSearchCore : InstantSearch.SingleIndexSearcher: received results - index: challenges query: “” hits count: 16 in 1ms

Optional(16)

But then the

   func reload() {
       challengeCollectionView?.reloadData()
    }

was called and after that, I got the previous number of hits again.

2020-12-24T13:42:49+0100 info com.algolia.InstantSearchCore : InstantSearch.SingleIndexSearcher: received results - index: challenges query: “” hits count: 16 in 1ms
Optional(15)

I know, we can use observers to check if a new search result is added but I want to trigger that check manually. What would be the best way to do it?

Hi @kaan548,

I suppose you faced a race condition between HitsInteractor update queue and controller’s update performing on the main thread.
You can subscribe to HitsInteractor.onResultsUpdated event to be notified when a new results page received by the HitsInteractor.

I hope this answers your questions and wish you Happy Holidays.

1 Like

Hello @vladislav.fitc. Thanks for the hint. I will try it and update my results here :slight_smile:

I’m working on this same sort of issue.

I’ve noticed a discrepancy between hits.count and totalHitsCount. Essentially, I’ll be able to add/delete stuff and refresh the searcher without any problems, but once I start scrolling around my main index, these two values get out of sync.

Then updates and deletes are no longer reflected in the UI correctly, and tableView.reloadData() does nothing.

For example:

		searcher.onResults.subscribe(with: self) { (_, results) in
			print(results.hits.count)
			print(results.searchStats.totalHitsCount)
			if results.searchStats.totalHitsCount < 1 {
				self.showNoResultsUI()
				print("No results UI")
			 } else {
				print("There are results")
				self.showHits()
			}
		 }
		
		hitsInteractor.onResultsUpdated.subscribe(with: self) { _, results in
			DispatchQueue.main.async {
			print("Interactor Test")
			hitsTableController.tableView.reloadData()
			}

When I call searcher.search(), I get this as an output:

2020-12-29T15:33:39-0600 info com.algolia.InstantSearchCore : InstantSearch.SingleIndexSearcher: received results - index: LXIUfjLYsWgtRJGbdSsMluTr9GH3 query: "" hits count: 21 in 1ms
0
21

Whereas before I was getting

2020-12-29T15:33:27-0600 info com.algolia.InstantSearchCore : InstantSearch.SingleIndexSearcher: received results - index: LXIUfjLYsWgtRJGbdSsMluTr9GH3 query: "" hits count: 21 in 1ms
21
21

I’m guessing this has something to do with the offset. The end result of all this is that searcher.search() essentially do nothing until I manually type in “” into the search bar or something.

Just an update on this. Turning off infinite scrolling solves this problem, so it’s definitely related to that somehow.

Did you try this @kaan548? Any luck? I’ve noticed a similar problem when adding new items to my indices and reloading the data. It’s off by whatever the number of things I’ve added is. See my post here.

Hi @yulelogsean, happy new year :slight_smile: To be honest, I haven’t had the time yet. Will update you once I try it out. Take care!

Hello @vladislav.fitc, happy year new! I wish all of you a healthy and successful 2021.

I guess, using such an observer would not help me. I want to display objects of a particular index on a collection view. All the app users can see the objects of each other on that view. Means, when a new record is added to that particular index, the observer would notify about that but depending on the frequency of adding new objects to the index, this is probably not user-friendly since the collection view would refresh every time automatically.

Instead, I want to trigger the refresh manually. I hope, I could explain my purpose. What would be the best way to achieve that?

Thanks!

Hi @yulelogsean,

I tried to apply your code snippet above. It is the same behavior as it was in my case without using the searcher.onResults.subscribe mechanism. First, I receive the correct number of the search results but then the reload method is called multiple times and so, the number of hits turns to the previous value before the new record was added.

Have you achieved any progress? :smiley:

Hi @yulelogsean,

Indeed, hits.count contains the information about the number of hits you received for a concrete results page, while totalHitsCount contains the entire index hits count for your query.
Most likely you launch a query for a page n+1, while search results consists of n pages, so you receive an empty results page with hits.count equal to 0.

If you have infinite scrolling turned on, the necessary search request for each page is triggered automatically by the InstantSearch while you are accessing a hit using hitAtIndex method, so you are not supposed to call the search() method manually which can result in unexpected empty results page.

@kaan548, If I understand well your use case, you want to manually trigger refresh search results considering that the state of your index has changed. If so, you have to call HitsInteractor.notifyQueryChanged() method – this will clear the existing hits caches. Then you have to call SingleIndexSearcher.search() method that will launch a new search.

Thanks @vladislav.fitc !