In this blog we demonstrate how to use the Joining Data Provider offered by Oracle JET to automatically merge multiple sets of data into a single array. The joining data provider takes arrays of data and merge them based on join conditions of foreign-key in one array to a column with same values in another array. The merge is done automatically on the client side. It is important to mention that client-side data merge is probably not the best idea in terms of performance. Databases, after all, are much better at doing this type of data merging using SQL Joins. If you are using Visual Builder's Business Objects as the source of data for your application, accessors allow you to merge data with join queries easily. For external REST services another solution that can do these type of data mashups is Oracle Integration. But sometimes, you end up with a situation where the client side is the only place available for you to do the merge.

In the demo video below, we use an Array Data Provider (ADP) to store data about employees, coming from a business object, and another ADP to store data on countries from an external REST service. After fetching the data into the ADPs, we use two lines of code. The first defines a join information with the foreign key and the data collection, and the second creates a new joining data provider. The joining data provider uses the join information to merge the data between the arrays – in our example using the country field from the BO (two letter code) to map to the alpha2code column coming from the REST endpoint.

We then use that joining data provider as the base for a table, which allows us to add a reference to the sub object location.capital as the source of data for a column.

Here is the whole process end to end in a video:

The code of our action chain ends up looking like this:

define([
  'vb/action/actionChain',
  'vb/action/actions',
  'vb/action/actionUtils',
  'ojs/ojjoiningdataprovider'
], (
  ActionChain,
  Actions,
  ActionUtils,
  JoiningDataProvider
) => {
  'use strict';

  class vbEnterChangeListener extends ActionChain {

    /**
     * @param {Object} context
     */
    async run(context) {
      const { $page, $flow, $application } = context;

      const runInParallelResult = await Promise.all([
        async () => {

          const callRestBusinessObjectsGetallEmployeesResult = await Actions.callRest(context, {
            endpoint: 'businessObjects/getall_Employees',
          });

          $page.variables.EmpADP.data = callRestBusinessObjectsGetallEmployeesResult.body.items;
        },
        async () => {

          const callRestCountriesGetAllResult = await Actions.callRest(context, {
            endpoint: 'Countries/getAll',
          });

          $page.variables.CountryADP.data = callRestCountriesGetAllResult.body;
        },
      ].map(sequence => sequence()));

      let countryJoin = {
        foreignKeyMapping: { foreignKey: 'country' },
        joinedDataProvider: $page.variables.CountryADP
      };
      $page.variables.JoinDP = new JoiningDataProvider($page.variables.EmpADP, {
        joins: { location: countryJoin }
      });
    }
  }

  return vbEnterChangeListener;
});