When one observable is linked to data in another observable, it creates a third observable that emits mapped data

Although this question may seem simple to a seasoned professional, I have struggled to wrap my head around it despite trying multiple approaches.

In my code, I have an observable observable1 that contains a list of keys like:

[
 key1,
 key3,
 key4,
 ..
]

The second observable observable2 contains data with some keys from observable1 mapping to them. It looks something like:

[
 {key1, val1},
 {key2, val2},
 {key3, val3},
 {key4, val4},
 ..
]

Assuming each key in observable1 has a corresponding mapping in observable2, I want to create a new observable observable3 that only emits the data mapped to by a key in observable1.

Using the example provided, the expected output should omit the data for key2 and look like:

[
 {key1, val1},
 {key3, val3},
 {key4, val4},
 ..
]

This result should be logged to the console after subscribing.

How can this functionality be achieved using rxjs? Just for your information, I am working with typescript.

Answer №1

In my response on this thread, I explained that achieving what you're describing is not feasible. Observables represent continuous streams of events, which could be triggered by various actions like user interactions or incoming messages. When an event occurs in `observable2`, it's unpredictable whether all the events from `observable1` have been received, making it uncertain if its key will be present in the stream.

However, what can be done is checking if an object's key exists within the set of keys previously received from `observable1` up to a certain point in time. The ideal method to accomplish this would involve aggregating `observable1` into a Behavior containing a set of keys using accumB, and subsequently filtering `observable2` based on the current value of that Behavior. Unfortunately, the RxJS API lacks support for the Behavior type, eliminating this elegant solution and forcing us to resort to manipulating mutable variables to store previously seen keys at any specific moment in time. We then proceed to filter `observable2` by referencing this variable for key comparison.

type KeyValuePair<K, V> = { key: K, val: V };

function filterByKey<K, V>(
    keys: Observable<K>,
    o: Observable<KeyValuePair<K, V>>
): Observable<KeyValuePair<K, V>> {
    var seenKeys: K[] = [];

    keys.subscribe(key => {
        if (seenKeys.indexOf(key) === -1) {
            seenKeys.push(key);
        }
    });

    return o.filter(x => seenKeys.indexOf(x.key) !== -1);
}

(Note: Due to working without an editor, there might be some errors in the code snippet, but the concept remains intact.)

Answer №2

It seems like you're looking for a way to extract specific values based on keys from multiple objects. One approach could be:

const dataKeys = Rx.Observable.fromArray(['key1','key3', 'key4'])
const dataObjects = Rx.Observable.fromArray([
  {key1: 'val1'},
  {key2: 'val2'},
  {key3: 'val3'},
  {key4: 'val4'}
])

const filteredData = dataKeys
  .flatMap(key => dataObjects.skipWhile(obj => !obj.hasOwnProperty(key)).take(1))

This code snippet processes each key in dataKeys, filtering out objects in dataObjects until the specified key is found, then emitting that object. Just keep in mind that if the key order is mixed, this method may not work as expected.

If your data is static and not received asynchronously, using Observables might not be necessary. In such cases, you can directly filter the objects based on key matches like so:

const keysToFilter = ['key1','key3', 'key4']
const dataObjs = [
  {key1: 'val1'},
  {key2: 'val2'},
  {key3: 'val3'},
  {key4: 'val4'}
]

const extractedValues = dataObjs.filter(obj => keysToFilter.includes(Object.keys(obj)[0]))

Answer №3

Yesterday, a question similar to this one was asked: RxJs: updating values in a list from an other stream identified by an ID

If the number of items and their order is not guaranteed, you can collect all items from both observable1 and observable2, then merge them into a single Observable:

let observable1 = Observable.from(['key1', 'key3', 'key4']);
let observable2 = Observable.from([{id: 'key1', val: 'val1'}, {id: 'key2', val: 'val2'}, {id: 'key3', val: 'val3'}, {id: 'key4', val: 'val4'}]);

let observable3 = Observable.forkJoin(
  observable1.toArray(),
  observable2.toArray(),
  (keys1, results1) => {
    let results = [];
    keys1.forEach(key => {
      results1.forEach(result => {
        if (key === result.id) {
          results.push(result);
        }
      });
    });

    return results;
  });

observable3
  .subscribe(val => console.log(val));

The main drawback here is that you need to gather all items from both Observables before merging them.

This code snippet will output the following to console:

[ { id: 'key1', val: 'val1' },
  { id: 'key3', val: 'val3' },
  { id: 'key4', val: 'val4' } ]

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ensuring strictNullChecks in Typescript is crucial when passing values between functions

When using the --strictNullChecks flag in TypeScript, there seems to be an issue with inferring that an optional property is not undefined when the check occurs in a separate function. (Please refer to the example provided, as articulating this clearly is ...

Implementing computed properties: A guide to incorporating type setting

I currently have two separate interfaces defined for Person and Dog. interface Person { name: string; weight: number; } interface Dog { name: string; mass: number } const specificAttribute = isDog ? 'mass' : 'weight'; ...

Struggling to bring in { useActionState } from 'react' while trying to follow the latest next.js tutorial with next.js v15.0.0-canary.28, react v19.0.0-rc, and types/react v18.2.21

Currently, I am following the tutorial on next.js available at https://nextjs.org/learn/dashboard-app I have reached chapter 14, which focuses on enhancing accessibility, located at https://nextjs.org/learn/dashboard-app/improving-accessibility During on ...

The proper method for organizing a nested array object - an obstacle arises when attempting to sort the array

I have a collection of data fetched from Web API 2.2 stored in an Angular array as objects. Each object represents a Client and includes properties like name, surname, and a collection of contracts assigned to that client. Here is the interface definition ...

Angular 9 - Refresh page while redirecting to the same URL, triggering only the API call specific to the current page

Is there a way to redirect to the same URL and also refresh the page without calling all APIs from the beginning of the application? I have attempted using an anchor tag with href, but it results in refreshing the entire page and fetching all APIs again. I ...

Building upon the foundation: Extending a base component in Angular

I have a Base Component that is extended by its children in Angular. However, when creating a new Component using angular-cli, it generates html and css files that I do not need for the base component. Is there a way to create a Base Component without inc ...

What is the process for installing all TypeScript definition files based on the packages.json file?

I have a project where I utilize a package.json file and run npm install to download all the required dependencies. Now, I am looking for a way to automatically install all typescript definition files based on the package.json. How can I accomplish this? ...

Sort the observable array by the property of its objects

Currently, I have an array of observables that I am iterating through using an *ngFor loop with the async pipe. I want to filter the observables based on a specific property value within the object. Starting array: [{ name: test1, type: type1}, { nam ...

The importance of specifying return types in Express routes when using TypeScript

Trying to maximize my use of TypeScript, I steer clear of any whenever I can. Express routes are often defined in this manner: import { Request, Response } from "express"; myRouter.route("/foo").post((req: Request, res: Response): Response => { ret ...

What is the functionality and purpose of reselect's createStructuredSelector in a Typescript environment?

Can someone explain to me how the reselect method createStructuredSelector operates in Typescript? The code snippet I often come across is as follows: export interface SomeProps { readonly property1: string; readonly property2: boolean; readonly ...

Steps for constructing an object literal with a property designated as the `keyof` type

Struggling to articulate my question, here is a simplified code snippet outlining what I aim to accomplish. class Example<T, TId extends keyof T> { public create(id: T[TId]): T { return { [TId]: id, // Encounter an error at this point. Ob ...

Transitioning from Angular Http to HttpClient: Overcoming Conversion Challenges

Currently, I am in the process of converting my old Angular app from Http to HttpClient. While working on the service.ts section, I encountered an error that I am struggling to resolve: ERROR Error: Cannot find a differ supporting object '[object Ob ...

How can we activate intellisense for a Vue component's template HTML?

Although I am still fairly new to Vue, I have a strong background in Typescript and Angular. Currently, I am embracing Typescript and utilizing the vue-class-component and vue-property-decorator libraries following the recommendations in the Vue documentat ...

Can the hexadecimal value from an input type color be extracted and used to populate form fields that will then be displayed in a table after submission?

Hello everyone, I'm new to this platform and seeking guidance on how to improve my post! I recently created a CRUD app using Angular. It consists of a basic form with 4 fields, a color picker using input type='color', and a submit button. U ...

Using Angular 6 HttpClient to retrieve an object of a specific class

Previously, we were able to validate objects returned from http api calls using the instanceof keyword in Angular. However, with the introduction of the new HttpClient Module, this method no longer works. I have tried various simple methods, but the type c ...

Guide to encapsulating an asynchronous function in a promise

I am in need of wrapping an asynchronous function within a promise to ensure synchronous execution. The reason behind this is that I must obtain a result from the asynchronous function before proceeding with the program's execution. Below is the rele ...

What is the best way to enhance a react-bootstrap component with TypeScript?

Currently, I am utilizing <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6f1d0a0e0c1b420d00001b1c1b1d0e1f2f5e415f415f420d0a1b0e415e5b">[email protected]</a> and delving into the development of a customized Button ...

Using "array_agg" in a "having clause" with Sequelize

I am facing a particular scenario with my database setup. I have three tables named computers, flags, and computerFlags that establish relationships between them. The structure of the computerFlags table is as follows: computerName | flagId computer1 | ...

Exploring the inner components of an entity without the need for external tools

I am currently enhancing TypeScript usage in a project by implementing generics. The challenge I am facing involves dealing with a complex object retrieved from the backend, which consists of a class with numerous attributes, most of which are classes them ...

Learn how to dynamically activate an icon in Angular to enhance user interaction

HTML Code: The Zoom Component <div class="zoom py-3"> <i nz-icon nzType="minus" (click)="zoomToggle(false)" nzTheme="outline"></i><br> <i nz-icon nzType="plus" (click)=&q ...