Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RXJS Repeat query until a condition is met?

Tags:

angular

rxjs

I'm using an API that returns only a limited number of results, say 100.

I'd like to repeat a query until the return result set is < 100 which would mean I've got the last result.

So it would go like this:

  1. Make query
  2. Is result set less than limit? If so, do again and append results.
  3. Once result set is less than limit, emit the final result.
like image 702
Charlie Avatar asked Aug 01 '18 18:08

Charlie


4 Answers

 stop$: Subject = new Subject();

 query$.pipe(takeUntil(this.stop$)).subscribe( result => {
    if(result < limit) 
       this.stop$.next();
       this.stop$.complete();
     }
   else {
      process result, i.e append somewhere...
   }
 });

Note his is the RxJs 6 syntax. For readability you can extract the subscribe logic in a method.

Maybe working with takeWhile is easier in this case:

doQuery: boolean = true;

 query$.pipe(takeWhile(()=> this.doQuery).subscribe( result => {
    if(result < limit) 
       this.doQuery = false;
     }
   else {
      process result, i.e append somewhere...
   }
 });
like image 109
René Winkler Avatar answered Oct 18 '22 22:10

René Winkler


We can also use the repeat operator:

this.queryData().pipe(
    repeat(),
    filter(data => this.checkLimit()),
    take(1)
).subscribe(result => console.log(result));

Note: the take(1) is needed to stop the repeat loop.

If we need a delay between retries, we can do:

repeat({delay: 1000})
like image 44
ebrehault Avatar answered Oct 18 '22 20:10

ebrehault


You can use the expand operator for a simple "conditional repeat" behavior.

Just for the example, instead of a result set I changed the query to return a number. The following keep querying until the retrieved number is less than 100

const { defer, empty } = rxjs;
const { expand, toArray} = rxjs.operators;

const query$ = defer(async () =>  Math.floor(Math.random()*1000));
   
query$
  .pipe(
    expand(result => result < 100 ? empty() : query$),
    toArray()
  )
  .subscribe(console.log);
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>
like image 15
ZahiC Avatar answered Oct 18 '22 20:10

ZahiC


You can also use RXJS Interval with TakeWhile operator. Here is the sample code

In Component:

return Observable
  .interval(250)
  .flatMap(() => this.getQueryData())
  .takeWhile(data => this.checklimit(data))
  .subscribe(result => console.log(result);

getQueryData(){
   // HTTTP API call 
}

checklimit(){
  // return true/false
}
like image 7
Suresh Kumar Ariya Avatar answered Oct 18 '22 20:10

Suresh Kumar Ariya