简体   繁体   English

RxJs 唯一地合并两个可观察对象

[英]RxJs merging two observables uniquely

I am using rxjs to build a searching and filtering system in an angular App.我正在使用 rxjs 在 angular 应用程序中构建搜索和过滤系统。

I have the following:我有以下内容:

interface User{ //exmaple model
 _id: string;
 name: string;
}

filters$ = new BehaviorSubject<Array<User>>([]);
search$ = new BehaviorSubject<Array<User>>([]);

// I use these two and merge them in another function as following

const myData$ = merge(this.search$.asObservable(), this.filters$.asObservable())
.pipe(distinctUntilChanged(distinctCheck))

With the utility function distinctCheck being something like:使用实用程序 function distinctCheck类似于:

const distinctKey = (elem) => {
    if(elem === null){
      return elem
    }
    if(this.hasId(elem)){
      return elem["_id"];
    }
    if(this.hasName(elem)){
      return elem["name"]
    }
    return this.createComparisonString(elem)
  }

But this biges me either one or the other observable.但这让我觉得其中一个或另一个可观察到的。 So my question is:所以我的问题是:

How can I merge the two observables and emit only the values that are common to both arrays?如何合并两个 observables 并只发出 arrays 共有的值? Where sometimes filters$ might emit an array of 30 elements.有时 filters$ 可能会发出一个包含 30 个元素的数组。 And sometimes search$ might emit an array of only 2 elements?有时 search$ 可能会发出一个只有 2 个元素的数组?

IE: IE:

if filter$ contains:如果filter$包含:

[{_id:'1', name:'jhon'},{_id:'2', name:'doe'},{_id:'3', name:'jolly'},{_id:'4', name:'some random dude'},{_id:'5', name:'some random other dude'},{_id:'6', name:'johny'},{_id:'7', name:'bravo'}]

and search$ contains:并且search$包含:

[{_id:'1', name:'jhon'},{_id:'101', name:'myDoe'},{_id:'301', name:'some-jolly'},{_id:'4', name:'some random dude'}, {_id:'7', name:'bravo'}]

I would like myData$ to emit something like:我希望myData$发出类似的内容:

[{_id:'1', name:'jhon'},{_id:'4', name:'some random dude'}, {_id:'7', name:'bravo'}]

Thank you all: :)谢谢你们: :)

The compare function of distinctUntilChanged operator is used to tell if the previous emission is different than the current emission. distinctUntilChanged运算符的compare function 用于判断先前的发射是否与当前的发射不同。

As I understood your question, you are looking for intersection between the search and filter arrays.据我了解您的问题,您正在寻找searchfilter arrays 之间的交集。

First, use combineLatest operator to get notified whenever search$ of filter$ emits.首先,使用combineLatest运算符在filter$search$ $ 发出时得到通知。
Then, you can use something like lodash's intersectionWith to get the arrays intersection.然后,您可以使用类似 lodash 的intersectionWith来获得 arrays 交点。

Your code should look something like this:您的代码应如下所示:

const comperator = (search, filter) => filter._id === search._id && filter.name === search.name; 

const myData$ = combineLatest(search$, filter$).pipe(
  map(([search, filter]) => intersectionWith(search, filter, comperator))
);

You can check the full running code in this stackblitz您可以在此 stackblitz中查看完整的运行代码

Something like this should work:像这样的东西应该工作:

const filters$ = new BehaviorSubject<Array<{ id: string }>>([]);
const search$ = new BehaviorSubject<Array<{ id: string }>>([]);

const combinedAndFiltered$ = combineLatest(filters$, search$)
    .pipe(map(([filters, searches]) => {
        return filters.filter(filter => !!searches.find(search => search.id === filter.id));
    }));

combinedAndFiltered$.subscribe(console.log)

You could actually achieve it with plain Javascript.您实际上可以使用普通的 Javascript 来实现它。

 var filterArr = [{_id:'1', name:'jhon'},{_id:'2', name:'doe'},{_id:'3', name:'jolly'},{_id:'4', name:'some random dude'},{_id:'5', name:'some random other dude'},{_id:'6', name:'johny'},{_id:'7', name:'bravo'}] var searchArr = [{_id:'1', name:'jhon'},{_id:'101', name:'myDoe'},{_id:'301', name:'some-jolly'},{_id:'4', name:'some random dude'}, {_id:'7', name:'bravo'}] var data = filterArr.filter(userFilter => searchArr.some(userSearch => userFilter._id == userSearch._id)) console.log(data);

As for the observables, you could try to combine them using combineLatest method.至于 observables,您可以尝试使用combineLatest方法组合它们。

const myData$ = combineLatest(this.search$.asObservable(), this.filters$.asObservable()).pipe(
  map(([filterArr, searcheArr]) => filterArr.filter(userFilter => searchArr.some(userSearch => userFilter._id == userSearch._id)))
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM