Observable: получить уникальные значения массива из документов коллекции - PullRequest
1 голос
/ 27 марта 2019

Каков наилучший способ создания списка уникальных значений из массивов Firestore?

Каждый документ в коллекции может иметь любое количество категорий, записанных в массиве документов «category».

Я пытаюсь получить все уникальные категории значений массива для заполнения параметров фильтрации, поэтому мне нужно быть уверенным, что есть отель для этой категории.Я не могу использовать только список всех категорий из другой коллекции.

Angular 8, Firestore, angularfire 2, Ionic 4

Observable:

this.hotels = afs.collection('hotels', ref => ref.where('city_id', '==', cityId).orderBy('reviews_number', 'desc')).valueChanges();

Компонент html:

<li *ngFor="let hotel of hotels | async">
{{ hotel.categories }}
</li>

Результат:

wifi
wifi
wifi,pool,center
pool

И я не могу понять, как лучше всего получать уникальные значения из массивов, чтобы иметь возможность заполнять раскрывающийся список всеми вариантами уникальных значений.

wifi,pool,center

Ответы [ 2 ]

1 голос
/ 27 марта 2019

Чтобы было проще, я бы предложил использовать отдельную переменную для размещения ваших выпадающих значений, подписаться на значения Firestore и затем извлечь уникальные значения

Машинопись:

class MyComponent {
  dropDownOptions: Array<any> = [];
  someMethod() { // only called once in the component
    this.hotels = afs.collection('hotels', ref => ref.where('city_id', '==', cityId)
      .orderBy('reviews_number', 'desc'))
      .valueChanges();
    this.hotels.subscribe((hotels) => {
      const options: Array<string> = hotels.reduce((prevValue, hotel) => {
        return [...prevValue, ...hotel.categories];
      }, []);

      this.dropDownOptions = options.filter(this.onlyUnique); // get unique values
    })
  }

  onlyUnique(value, index, self) { 
    return self.indexOf(value) === index;
  }

}

HTML:

<select>
  <option *ngFor="let option of dropDownOptions" value="{{option}}">
    {{ option }}
  </option>
</select>

UPDATE:

В HTML была опечатка. То есть dropdownOptions должен был быть dropDownOptions. Починил это. Кроме того, я поместил пример Stackblitz , который демонстрирует поведение.

1 голос
/ 27 марта 2019

Вы можете использовать mergeMap () RxJS для испускания одиночных отелей объектов, Different () для фильтрации дубликатов на основе id и заархивировать его обратно в массив с
toArray ()

this.hotels = afs.collection('hotels', ref => ref.where('city_id', '==', cityId)
  .orderBy('reviews_number', 'desc'))
  .valueChanges()
  .pipe(mergeMap(hotels => hotels), distinct(hotel => hotel.id), toArray());

Я не работал с Firebase, но, если бы мне пришлось угадывать, valueChanges () - это бесконечный поток. В этом случае toArray () не будет работать, и вам нужно будет scan () значений и вставить в массив .

this.hotels = ...valueChanges().pipe(
  mergeMap(hotels => hotels), 
  distinct(hotel => hotel.id), 
  scan((acc, val) => acc.concat(...val), []));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...