2

Is there any RxJS function that could help me to get a subset of an array with the changed objects?

Something like distinctUntilChanged but that I would return me an array with the changed objects instead of all the objects?

An example of my environment would be:

this.store.select(mySelector) -> observable for a list of objects

I want to pipe my observable that is getting updated almost every 100ms to return me only the updated objects instead of the full list. I have been thinking about the best solution for this since the performance will matter in this case but I can't think of anything, anyone got any suggestions?

Edit: I thought about doing a distinctUntilChanged and assign the prev and current array to variables and then work with those variables on a map but it doesn't seem the best option neither that it will have a good performance.

Solution: I got to a solution by mixing @MoxxiManagarm answer with this one How can I get which object changed in a BehaviourSubject in RxJs? and the result was something like:

myComparator = (prev: any, curr: any) => {
    const returningValue = [];

    curr.forEach((obj) => {
        const prevObj = prev.find((v) => v.id === obj.id);
        if (!prevObj) {
            returningValue.push(obj);
        } else {
            if (JSON.stringify(prevObj) !== JSON.stringify(obj)) {
                returningValue.push(obj);
            }
        }
    });
    return returningValue;
}

this.obs$ = this.store
        .select(mySelector)
        .pipe(
            startWith([]),
            pairwise(),
            map(([prev, curr]) => this.myComparator(prev, curr))
        );
João Silva
  • 531
  • 4
  • 21
  • 40
  • 1
    There is no rxjs operator that detects changes in arrays or objects. What you're asking for is an operation on two arrays. [How to get the difference between two arrays in JavaScript?](https://stackoverflow.com/q/1187518/9423231) Can you give an example of what your observable emits and what should be emitted. – frido Aug 24 '20 at 09:27
  • @fridoo it emits a list of objects that contains GPS coordinates and other properties, but to update it in an integration with google maps I want to update only the objects that changed, that's why I wanted to compare both previous and current array and then get only the changed objects. – João Silva Aug 24 '20 at 10:09
  • Does this answer your question? [How can I get which object changed in a BehaviourSubject in RxJs?](https://stackoverflow.com/questions/60865331/how-can-i-get-which-object-changed-in-a-behavioursubject-in-rxjs) – frido Aug 24 '20 at 10:19
  • @fridoo I'm trying to implement that in a way to work with my array, I'll let you know later if I succeed, thank you – João Silva Aug 24 '20 at 10:48

1 Answers1

2

You could use pairwise and a function who compares both emitions. In my example I used lodash's without.

const data = of(
  ['A'],
  ['A', 'B'],
  ['A', 'B'],
  ['AA', 'B'],
);

data.pipe(
  startWith([]),
  pairwise(),
  map(([l, r]) => without(r, ...l)),
).subscribe(console.log);

Output:

["A"]
["B"]
[]
["AA"]

Stackblitz: https://stackblitz.com/edit/rxjs-wn9rxy?file=index.ts

MoxxiManagarm
  • 8,735
  • 3
  • 14
  • 43
  • I can understand the logic of it but someone it's not working with my objects, I still receive my full array even when the objects didn't change between the updates. – João Silva Aug 24 '20 at 10:49
  • Well, your solution gave me a good idea in how to mix it with the one in here: https://stackoverflow.com/q/1187518/9423231 To achieve my goal, I'll keep you updated if I could reach the solution I'll just mark it as an answer and update my question with my solution – João Silva Aug 24 '20 at 11:02