Skip to content
This repository has been archived by the owner on Jan 12, 2019. It is now read-only.

[question] Why do you get a snapshot that contains no hits, before the actual response that contains the hits? #158

Open
chrillewoodz opened this issue May 3, 2017 · 3 comments

Comments

@chrillewoodz
Copy link

I'm struggling on something that works sporadically, and I cannot figure out what's causing it.

Basically what I've found is that you get an object containing 0 hits and a total of 0.

Then after that you get the actual response, let's say 8 hits and a total of 8.

What I can't wrap my head around is where the empty hits object is coming from, because when I log stuff in the backend I can never see it. And the data that's being written to Firebase is the non-empty hits object as far as I can see.

Does flashlight write a response to Firebase twice but it's too fast for me to see? Because the function that stores the results gets stuck on the first response with 0 hits (most of the times, like I said this only happens sporadically which makes it even harder to understand).

This is my tweaked implementation:

  performSearch(options: any, skip = 1): Observable<any> {

    const query: any = this.buildQuery(options);

    const ref: any = firebase.database().ref().child('search');
    const key: string = ref.child('request').push(query).key;

    ref.child(`response/${key}`).on('value', this.storeResults.bind(this));

    return this.store.select('elasticsearch').skip(skip).map((elasticsearch: IElasticSearchStorage) => elasticsearch[key]);
  }

  storeResults(snapshot) {

    // Wait until we get data
    // NOTE: If I remove this, the console.log below will log:
    //  null 
    //  the actual response with the hits
    //  null
    if (!snapshot.exists()) {
      return;
    }

    console.log(snapshot.val());

    // Stop listening once data has arrived and remove the listener
    snapshot.ref.off('value', this.storeResults);
    snapshot.ref.remove();

    const payload: any[] = snapshot.val() && snapshot.val().hits ? snapshot.val().hits.hits : [];

    this.store.dispatch({type: ElasticSearchActions.SAVE_QUERY_RESULTS, payload: {type: snapshot.key, data: payload}});
  }

The strange thing is, if I remove the snapshot.exists() if statement, I don't get the "fake" response at all, but instead I get null, the real response and then null again after that.

What is going on? :| 

@katowulf
Copy link
Contributor

katowulf commented May 4, 2017

Keep in mind that this is an asynchronous operation on the server side (i.e. talking to ElasticSearch). If you start listening on the path while the server is still processing the reply, then you're going to get null first (expected) before the server actually writes any data there.

Note also that your are removing the ref in storeResults(), which is also going to trigger ref.child(response/${key}`).on('value'...) to run again with null. So I'd expect at least 2 calls with null with the way you've set this up.

@chrillewoodz
Copy link
Author

But what I don't understand is why I get a response object looks like:

{
  hits: {
    total: 0
  },
  took: 1,
  _shards: {
    failed: 0,
    successful: 5,
    total: 5
  }
}

Even though this is never pushed to Firebase (from what I can see), and the flashlight server shows that there are 8 results. Do you have any suggestions on what I should do differently in my example?

@katowulf
Copy link
Contributor

katowulf commented May 4, 2017

Can you create a minimal repro I can run to see the problem?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants