【问题标题】:Observable: get unique array values from collection documentsObservable:从集合文档中获取唯一的数组值
【发布时间】:2019-03-27 19:35:59
【问题描述】:

从 Firestore 数组创建唯一值列表的最佳方法是什么?

集合中的每个文档都可以有任意数量的类别,这些类别写在文档数组“类别”中。

我正在尝试获取数组值的所有唯一类别来填充过滤选项,因此我需要确保该类别有一家酒店。我不能只使用其他集合中的所有类别列表。

Angular 8、Firestore、angularfire 2、Ionic 4

可观察:

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

【问题讨论】:

    标签: angular firebase ionic-framework google-cloud-firestore


    【解决方案1】:

    为了保持简洁,我建议使用单独的变量来托管您的下拉值,然后订阅 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>
    

    更新:

    HTML 中有错字。 IE。 dropdownOptions 应该是 dropDownOptions。修复。 另外,我放了一个 Stackblitz example 来演示这种行为。

    【讨论】:

    • 感谢您的帮助,最终代码应如下所示:pastebin.com/B2nv5FAh 但 dropdownOptions 为空
    • 在 HTML 中执行 {{ dropDownOptions }} 我得到了唯一值! wifi,pool,center - 它可以工作,只是 *ngFor 不返回值
    • @TedAce 请检查我的答案(更新部分),我添加了一个演示解决方案的 stackblitz 示例。希望对您有所帮助。
    • 有效,我怎么没有检查类型错误:))) 也许你也知道如何排除空值?现在也包括空值(酒店没有任何类别)。再次感谢
    • 您可以将代码中的return [...prevValue, ...hotel.categories];更改为return [...prevValue, ...hotel.categories.filter(category =&gt; category !== "")];,以排除空字符串作为类别。另外,如果他们对您有帮助,请给答案和 cmets 投票 :) 谢谢,编码愉快!
    【解决方案2】:

    您可以使用 RxJS 的 mergeMap() 发出单个 hotel 对象,distinct() 根据 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() 将值推入 array

    this.hotels = ...valueChanges().pipe(
      mergeMap(hotels => hotels), 
      distinct(hotel => hotel.id), 
      scan((acc, val) => acc.concat(...val), []));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-15
      • 1970-01-01
      • 2017-08-16
      • 1970-01-01
      • 2020-06-14
      • 1970-01-01
      • 2020-04-14
      • 1970-01-01
      相关资源
      最近更新 更多