"Combine data streams efficiently with RxJS using #groupBy to create groups of observable

I am trying to zip grouped observables in order to form the cartesian product of related groups. However, when I run the code below, only the child observable groups emit values inside the #zip function - why is that?

Link to code snippet

var parent = Rx.Observable.from([1,2,3]).publish();
var child = parent.map(x => x).publish();
var groupedParent = parent.groupBy(x => x);
var groupedChild = child.groupBy(x => x);

Rx.Observable.zip([groupedChild, groupedParent])
  .map(groups => {
    groups[0].subscribe(x => console.log('zipped child ' + x)); // -> emitting
    groups[1].subscribe(x => console.log('zipped parent ' + x)); // -> not emitting
  })
  .subscribe();

groupedChild.subscribe(group => {
  group.subscribe(value => console.log('child ' + value)); // -> emitting
});

groupedParent.subscribe(group => {
  group.subscribe(value => console.log('parent ' + value)); // -> emitting
});

child.connect();
parent.connect();

Edit: As pointed out by user3743222, the data emitted by groupBy are considered "hot" observables. The subscription to the parent group (groups[1]) occurs after the first values have already been emitted. This is because #zip function waits for both groupedChild and groupedParent to emit, with the latter emitting sooner (resulting in its groups emitting values before the #zip function is executed).

Answer №1

I made changes to the code like this:

var totalChildren = 0, totalParents = 0;
function emits ( person ) {
  return function ( item ) {console.log(person + " releases : " + item);};
}
function checkTotal ( person ) {
  return function ( ) {
    if (person === "parent") {
      totalParents++;
    }
    else {
      totalChildren++;
    }
    console.log("Checking : Total parents = " + totalParents + ", Total children = " + totalChildren );
  };
}
function verify ( person, location ) {
  return function ( data ) {
    console.log("Verification : " + person + " : " + location + " :" + data);
  };
}
function finish ( person ) {
  return function () { console.log(person + " finished!");};
}
function combine ( person ) {
  return function ( data ) { console.log('combined ' + person + ' ' + data); };
}
function additionBy1 ( number ) {
  return number + 1;
}
function error () {
  console.log('error');
}

var mom = Rx.Observable.from([1, 2, 3, 4, 5, 6])
    .do(emits("parent"))
    .publish();
var child = mom
    .map(function ( x ) {return x;})
    .do(emits("child"))
//    .publish();

var groupedMom = mom
    .groupBy(function ( x ) { return x % 2;}, function ( x ) {return "P" + x;})
    .do(checkTotal("parent"))
    .share();

var groupedChild = child
    .groupBy(function ( x ) { return x % 3;}, function (x) {return "C" + x;})
    .do(checkTotal("child"))
    .share();

Rx.Observable.zip([groupedChild, groupedMom])
//    .do(function ( x ) { console.log("zip args : " + x);})
    .subscribe(function ( groups ) {
                 groups[0]
                     .do(function ( x ) { console.log("Child group emitted value : " + x);})
                     .subscribe(combine('child'), error, finish('Child Group'));
                 groups[1]
                     .do(function ( x ) { console.log("Parent group emitted value : " + x);})
                     .subscribe(combine('parent'), error, finish('Parent Group'));
               }, error, finish('zip'));

//child.connect();
mom.connect();

This is the result :

"parent releases : 1"
"child releases : 1"
"Checking : Total parents = 0, Total children = 1"
"Checking : Total parents = 1, Total children = 1"
"Parent group emitted value : P1"
"combined parent P1"
"parent releases : 2"
"child releases : 2"
"Checking : Total parents = 1, Total children = 2"
"Checking : Total parents = 2, Total children = 2"
"Parent group emitted value : P2"
"combined parent P2"
"parent releases : 3"
"child releases : 3"
"Checking : Total parents = 2, Total children = 3"
"Parent group emitted value : P3"
"combined parent P3"
"parent releases : 4"
"child releases : 4"
"Child group emitted value : C4"
"combined child C4"
"Parent group emitted value : P4"
"combined parent P4"
"parent releases : 5"
"child releases : 5"
"Child group emitted value : C5"
"combined child C5"
"Parent group emitted value : P5"
"combined parent P5"
"parent releases : 6"
"child releases : 6"
"Parent group emitted value : P6"
"combined parent P6"
"Child Group finished!"
"Child Group finished!"
"Parent Group finished!"
"Parent Group finished!"
"zip finished!"

There are two key points to keep in mind:

  1. Differences between zip and grouping compared to subscription time

    • Grouping by creates observable items as expected for both parent and child.

    In the logs, you will see that Child generates three groups, while Parent generates two

    • Zip waits until there is one value from each source specified in the parameters to subscribe. In this scenario, it means subscribing to child and parent grouped-by observables only when they have both issued values. You will observe

      "Parent group emitted value : P1"
      only after matching numbers on
      "Checking : Total parents = 1, Total children = 1"
      .

    • You then subscribe to both grouped-by observables and log whatever comes out of them. The issue arises because the parent grouped-by observable has a value to pass on, BUT the child 'group-by' observable was created before and already passed its value, so you miss seeing that value when you subscribe late. Instead, you will see the subsequent values.

    • Hence, values in [1-3] create three new child grouped-by observables that you won't see, as you subscribe too late. However, you will see values in [4-6]. This can be confirmed in the log with entries like "combined child C4".

    • All values in the parent grouped-by observables will be visible as you subscribe to them immediately following their creation.

  2. connect and publish

    • The understanding of connect and publish may not be entirely clear, but since your child has the parent as a source, delaying connection to it is unnecessary. Connecting to the parent triggers the child to automatically emit its values, hence the modification I made to your code.

    • This addresses your current inquiry but may not align with your original goal of achieving a cartesian product. If necessary, consider rephrasing your intention as a question to explore alternative solutions provided by others.

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

Is there a way to retrieve all "a" tags with an "href" attribute that contains the term "youtube"?

My goal is to capture all a tags that have the href attribute containing the word youtube. This task requires the use of jquery. ...

How to remove the black border on a material-ui button

I am currently working with the material-ui datepicker and buttons. Whenever I click on the datepicker icon to select a date or any of the buttons, I notice a black border appearing. How can I remove this black border from the design? https://i.sstatic.ne ...

The design template is failing to be implemented on my personal server utilizing node.js

I've encountered an issue while developing the signup page on my local server using Bootstrap 4. The CSS is not getting applied properly when I run it locally, although it displays correctly in the browser. Can someone explain why this is happening? ...

How can the data controller of a model be accessed within a directive that has been defined with "this"?

I'm struggling with accessing data using a directive, especially when I have defined my models like this: vm = this; vm.myModel = "hello"; Here is an example of my directive: function mySelectedAccount(){ return { restrict: 'A&ap ...

Modifying the background image of div elements with JQuery in a loop function is ineffective when using Google Chrome

I am facing an issue in my application where I have a for loop to change the background image of two divs. The code snippet is as follows: for (var i = 0; i < length; i++) { $("div_" + (i + 1)).css("background-image", "../imageFile.png"); ...

Use .load() to set an image as background in the div

There is a block of code that is supposed to display images in a div with the class "img", but it isn't functioning correctly. Can you provide some guidance on how to fix this issue? <div class="other"><a href="/index1.html">Link1</a&g ...

Locate the unique symbol within an array

I am facing a challenge with validating user input in an input box where alphanumeric values are allowed along with certain special characters. I need to display an error message if the user enters a special character that is not supported by my applicatio ...

What are some ways to create a versatile wrapper?

I'm currently grappling with an issue involving my Formik fields. I need to utilize FastFields in certain scenarios and Fields in others within my FormikControl, a class designed for constructing formik inputs. The challenge lies in being able to swit ...

Broadcast the latest N occurrences

I am working on an Angular 6 application where I want to display the most recent N events from a continuous stream of events coming from a web-socket. Currently, the data is shown using RxJS Observable<Event[]>: <div *ngFor="let event of (wsEven ...

What flaws are present in this authentication system?

As a developer with a passion for coding, rather than a security expert, I came across The definitive guide to form-based website authentication, which highlighted the importance of SSL or complex algorithms in safeguarding login data from eavesdropping. D ...

ReactJs Error: Unable to access property value because it is undefined (trying to read '0')

I am currently attempting to retrieve and display the key-value pairs in payload from my JSON data. If the key exists in the array countTargetOptions, I want to show it in a component. However, I am encountering an error message stating Uncaught TypeError ...

Is there a way to use JQuery to dynamically generate a new select box with specific options?

I am looking to dynamically create a new select box based on the value selected in an existing select box using jQuery. Currently, the code we have implemented is not functioning correctly. <script src="http://code.jquery.com/jquery-1.5.min.js">&l ...

What is the best way to retrieve a collection of DOM elements in JSX?

I'm in need of rendering certain components only if a specific condition is met. To achieve this, I have written the following inside the render() method: return ( <div className={classes.root}> {registrationScreen && ( * ...

Dealing with 401 Errors: Navigating Redirects using Vue.js and

Currently, I am utilizing Vue.js along with axios in an attempt to create a generic API object as shown below: import router from './router' import auth from './auth' const axios = require('axios') export const API = axios.c ...

Ember - connecting to a JSON data source

Recently, I have been following a tutorial/example from codeschool and everything is going well. However, the example code includes the line: App.ApplicationAdapter = DS.FixtureAdapter.extend(); Now, I want to maintain all the existing functionality but ...

Replace Formik with useFormik to streamline your code

I have implemented Formik/Yup for validation on a page that triggers a GraphQL mutation. The code is functioning as expected: export default function RemoveUserPage() { const [isSubmitted, setIsSubmitted] = useState(false); const [isRemoved ,setIsRemo ...

Are these objects enclosed within a JavaScript array?

Are square brackets used to define arrays and curly brackets used for objects? Can you explain the following data structure: Some.thing = [ { "swatch_src" : "/images/91388044000.jpg", "color" : "black multi", "inventory" : { "F" : [ 797113, 797 ...

Is it possible to use multiple AJAX requests to automatically fill out form fields?

In my Backbone.js web application, there is a form with multiple dropdowns that need to be populated with data fetched from an API. Since all the application logic resides on the client side due to using Backbone.js, I want to avoid populating these dropd ...

Understanding intricate JSON structures with JavaScript

Here is the JSON structure that I am working with: var data = [ { "country":"Andorra", "code":"AD", "state":[ { "state_code":"AD1", "state_description":"aaAndorra1" }, { " ...

PHP failing to retrieve information

Having trouble with this specific file as it seems to be missing data in the address fields. Additionally, whenever "notes" are inputted, the Address data disappears. Any thoughts on how to resolve this issue? <tbody> ' ; $message .=&a ...