Get the first item that matches a condition in Observable

Viewed 778

I need to get, from an observable, the first item in payload.result which type is avatar:

let result = this.fileService.getAvatarByUserId(2).pipe(
  map((payload: Payload<FileModel[]>) => payload.result),
  first((result: FileModel[]) => result.type == 'avatar')
);

But I get error that "is not assignable to type 'Observable'"

How to solve this?

2 Answers

You can do one of the following based on your needs...

filter + take(1)

this.fileService.getAvatarByUserId(2)
      .pipe(
        map((payload: Payload<FileModel[]>) => payload.result),
        flatMap(uploads => uploads), // Flattens the array
        filter(upload => upload.type === 'avatar'), // filters anything that's avatart
        take(1) // return only the first
    ).subscribe(
      console.log
    );

OR

first(predicate function) -> my preference

this.fileService.getAvatarByUserId(2)
      .pipe(
        map((payload: Payload<FileModel[]>) => payload.result),
        flatMap(uploads => uploads), // Flattens the array
        first(upload => upload.type === 'avatar') // returns the first positive match
    ).subscribe(
      console.log,
      console.log // this is to log an error if no match found when the subscription completes
    );

OR filter + first

this.fileService.getAvatarByUserId(2)
      .pipe(
        map((payload: Payload<FileModel[]>) => payload.result),
        flatMap(uploads => uploads), // Flattens the array
        filter(upload => upload.type === 'avatar'), // filters anything that's avatart
        first() // returns the first value
    ).subscribe(
      console.log,
      console.log // this is to log an error if no match found when the subscription completes
    );

first operator can notify if the condition was not met when the subscription completes by adding the error method to the subscription -> see the subscription for the last two options (probably why i like this the most...)

see this in action

edited to add more clarity for the first operator based on @Jonathan Stellwag comments (thank you!!!)

You can use the filter and take operator.

let result = this.fileService.getFilesByUserId().pipe(
  filter(payload => payload.payload.result === 'avatar'),
  take(1)
);
Related