title: Filtering Observable of Array (Observable<Event[]>)
body: <p>Here is my scenario:</p>
  
  <ol>
  <li>I have 1000s of Events (Firebase objects) happening at various locations.</li>
  <li>I need to show list of Events to users, based on their location preferences.</li>
  <li>Some users might be interested in events from all 15 locations and some users might be interseted in events from only one location (out of 15 different locations)</li>
  <li>Also, I need to show only upcoming events and not past events (determined by the timestamp property <code>endDateLong</code>)</li>
  <li>So I apply location filter logic locally and time filter logic by using angualarFire <code>orderByChild</code></li>
  <li>At any time, it is sufficient to show only 30 immediate events to the user, even if they subcribed to all locationss and they should get all 1000 events.</li>
  </ol>
  
  <p>My Solution (design):</p>
  
  <ol>
  <li>I dont want to fetch all 1000s of events and filter them</li>
  <li>Rather I just want to fetch a small block (say 50) filter it with user's location preference.</li>
  <li>If I get 30+ events after applying the filter well and good. We can display the same in UI.</li>
  <li>But in case, if the filter reduces the 50 to just 10 events, I recursively call my function again to get next set (based on endDateLong) of 50 events.</li>
  <li>I repeat Point 4, till either I get 30+ events or till the whole array in Firebase gets exhausted.</li>
  </ol>
  
  <p>My working code:</p>
  
  <ol>
  <li><p>This recursive functions is working well and good and serves the purpose.</p>
  
  <pre><code>fetchFilteredEvents(startKey:number) {
  
  let self                =   this;
  let cacheKey            =   this.fireRoute.getPathForMetaEvents();
  let evListObs:FirebaseListObservable&lt;Event[]&gt;;
  
  evListObs               =   self.db.list(cacheKey, {
      query               :   {   
          orderByChild    :   'endDateLong',
          startAt         :   startKey,
          limitToFirst    :   50  
      }   
  }); 
  
  return evListObs.first().map(evList =&gt; {
      let cList           =   evList.filter(ev =&gt; {
  
          /** 
           * BEGIN: Check if event falls in any Preferred locations
           */
          let allBlocks   =   self.volService.me.locationPreferences.blocks;
          let prefBlockIDs=   Object.keys(allBlocks)
                                  .filter(b =&gt; { return allBlocks[b] }); 
          let matchingObj =   prefBlockIDs.find( bid =&gt; { return bid == ev.block.id } );
  
          // return true, if any matching block is found
          if (matchingObj)    return true;
          /** 
           * END: Check if event falls in any Preferred locations
           */
  
          return false;
      }); 
  
      self.eventCount     +=  cList.length;
  
      // If required 30 items are retrieved or event list is exhausted just return current list.
      // If not, recursively call the function again with timestampe of the last event and append it's return value to current array and return the whole appended list
      if (evList.length == 1 || self.eventCount &gt; 30) {
          return cList;
      } else {
          let lastEvent   =   evList[evList.length -1];
  
          console.log("Fetch next page @ ", lastEvent.endDate);
          console.log("Current list is ", cList);
          return self.fetchFilteredEvents(lastEvent.endDateLong).then(allEvents =&gt; {
              return allEvents.concat(cList);
          }); 
      }   
  
  }).toPromise();
  
  }   
  </code></pre></li>
  </ol>
  
  <p>Problem with this code:</p>
  
  <ol>
  <li>Let's say user prefers events from only one location.</li>
  <li>It means lots of fetched events are going to be filtered out and several recursions are gonna happen till I get 30 events.</li>
  <li>It takes several seconds and the UI is not updated till 30 events are fetched or the list is exhausted.</li>
  <li>The whole function blocks the UI update.</li>
  </ol>
  
  <p>What I want:
  I would like to improve the code somehow with just observables:</p>
  
  <ol>
  <li>So I can return my partial event array and populate the UI</li>
  <li>More than Point 1, I am eager to learn Observables good enough to handle this kind of scenarios :-)</li>
  </ol>
  
  <p>PS: It's Angular 2 (or 4) code and AngularFire2</p>
  
  <p>Any pointers?</p>
  
  <p>Update 1 - Conversion to Observables (Nothing much)</p>
  
  <pre><code>private fetchFilteredEvents(startKey:number) : Observable&lt;Event[]&gt; {
  
      let that                =   this;
      let cacheKey            =   this.fireRoute.getPathForMetaEvents();
  
      let evObs               =   that.db.list(cacheKey, {
          query               :   {   
              orderByChild    :   'endDateLong',
              startAt         :   startKey,
              limitToFirst    :   10  
          }
      }).map(evList =&gt; {
          let cList           =   evList.filter(ev =&gt; {
              // Filter logic goes here
          });
  
          that.eventCount     +=  cList.length;
  
          // If required 30 items are retrieved or event list is exhausted just return current list.
          // If not, recursively call the function again with timestampe of the last event and append it's return value to current array and return the whole appended list
          if (evList.length == 1 || that.eventCount &gt; 30) {
              return cList;
          } else {
              let lastEvent   =   evList[evList.length -1];
  
              console.log("Fetch next page @ ", lastEvent.endDate);
              console.log("Current list is ", cList);
  
              // THIS IS NOT WORKING. I am only getting the first 10 events. I think I should somehow merge the returning obserable of recursive calls to `that.fetchFilteredEvents()` to `evObs`, rather than array merging as done here.
              return that.fetchFilteredEvents(lastEvent.endDateLong).subscribe(nextList =&gt; {
                  console.log(nextList);
                  cList   =   cList.concat(nextList);
                  return cList;
              });
          }
  
      });
  
      this.currentList = evObs;
      return this.currentList;
  </code></pre>