When using Array.reduce(), group objects by a specific field and include all other fields in the corresponding grouped object

I'm trying to develop a group-by function for an object, where I can group an array based on a field and then merge all fields of the grouped documents from the array with their corresponding group-object fields.

const groupInDoc = (array, fieldname) => {
    let groupedResultDoc = array.reduce((carDocs, current) => {  
        let keyCount = Object.keys(current).length;
        let obj = {};
        for (let [key, value] of Object.entries(current)) { 
            console.log(`${key}: ${value}`);           

            //check if key matches the field name to group by.
            if (key == fieldname) {
            } else {
                obj[key] = value;
            }

        }      
        if (carDocs.hasOwnProperty(current[fieldname])) {
            carDocs[current[fieldname]] = obj;
        } else {            
            carDocs[current[fieldname]] =  obj;

        }  
        return carDocs;     
    }, Object.create({}));

    return groupedResultDoc;
}

I am facing a challenge in how to expand the fields of the grouped objects using other corresponding object fields from the array objects.

For example, if my grouped object includes a subdocument for a group key with an array field and a string field, I want to add new values from matching group objects to the existing array and combine strings together using "+". How can I achieve this?

UPDATE: Original data:

let doc = [
    {
        "car": "Ford",
        "prices": ["12", "3", "5", "1"],
        "model": "SUV"
    },
    {
        "car": "Ford",
        "prices": ["99","88","77"],
        "model": "T3"
    },
    {
        "car": "Toyota",
        "prices": ["33","44","55"],
        "model": "Subaru"
    },
    {
        "car": "Toyota",
        "prices": ["66", "50", "22"],
        "model": "Cheyenne"
    },
    {
        "car": "Peugeot",
        "prices": ["1","2","3"],
        "model" : "503"
    }
];

The current result is:

CarDocs:  { Ford: { prices: [ '99', '88', '77' ], model: 'T3' },
  Toyota: { prices: [ '66', '50', '22' ], model: 'Cheyenne' },
  Peugeot: { prices: [ '1', '2', '3' ], model: '503' } }

but it should be:

CarDocs:  { Ford: { prices: ["12", "3", "5", "1", '99', '88', '77' ], model: 'T3', 'SUV' },
  Toyota: { prices: [33","44","55", '66', '50', '22' ], model: 'Cheyenne', 'Subaru' },
  Peugeot: { prices: [ '1', '2', '3' ], model: '503' } }

Answer №1

You have the option to combine each object based on the key name in each iteration using the reduce method:

let doc = [{"car": "Ford","prices": ["12", "3", "5", "1"],"model": "SUV"},{"car": "Ford","prices": ["99","88","77"],"model": "T3"},{"car": "Toyota","prices": ["33","44","55"],"model": "Subaru"},{"car": "Toyota","prices": ["66", "50", "22"],"model": "Cheyenne"},{"car": "Peugeot","prices": ["1","2","3"],"model" : "503"}];

let CarDoc = doc.reduce((a, {car, prices, model}) => {
  if(a[car]) {
    prices.forEach(p => a[car].prices.push(p))
    a[car].model = [...a[car].model, model]
  } else {
    a[car] = {prices, model:[model]}
  }
  return a
}, {})

console.log(CarDoc)

For a less readable, single-line version:

let doc = [{"car": "Ford","prices": ["12", "3", "5", "1"],"model": "SUV"},{"car": "Ford","prices": ["99","88","77"],"model": "T3"},{"car": "Toyota","prices": ["33","44","55"],"model": "Subaru"},{"car": "Toyota","prices": ["66", "50", "22"],"model": "Cheyenne"},{"car": "Peugeot","prices": ["1","2","3"],"model" : "503"}];

let CarDoc = doc.reduce((a, {car, prices, model}) => a[car] ? {...a, [car]: {prices: a[car].prices.concat(prices), model: a[car].model.concat(model)}} : {...a, [car]: {prices, model:[model]}}, {})

console.log(CarDoc)

EDIT:

let doc = [{"car": "Ford", test: 'test', "prices": ["12", "3", "5", "1"],"model": "SUV"},{"car": "Ford", test: 'test', "prices": ["99","88","77"],"model": "T3"},{"car": "Toyota","prices": ["33","44","55"],"model": "Subaru"},{"car": "Toyota","prices": ["66", "50", "22"],"model": "Cheyenne"},{"car": "Peugeot","prices": ["1","2","3"],"model" : "503"}];

let CarDoc = doc.reduce((a, {car, ...rest}) => {
  Object.entries(rest).forEach(([k,v]) => {
    if(a[car]) {
      a[car][k] = [...a[car][k] || [], v]
    } else {
      a[car] = {...a[car], [k]: [v]}
    }
  })
  
  return a
}, {})

console.log(CarDoc)

Answer №2

Make sure to merge the values with the previous one instead of assigning new values in each iteration

let data = [{"car": "Ford","prices": ["12", "3", "5", "1"],"model": "SUV"},{"car": "Ford","prices": ["99","88","77"],"model": "T3"},{"car": "Toyota","prices": ["33","44","55"],"model": "Subaru"},{"car": "Toyota","prices": ["66", "50", "22"],"model": "Cheyenne"},{"car": "Peugeot","prices": ["1","2","3"],"model" : "503"}];

let result = data.reduce((accumulator,{car,prices,model:m})=>{
  accumulator[car] = accumulator[car] || {prices:[],model:[]}
  accumulator[car].prices = [...accumulator[car].prices, ...prices]
  accumulator[car].model = [...accumulator[car].model, m]
  return accumulator
},{})

console.log(result)

Answer №3

Check out my fantastic library blinq that offers a variety of functions to simplify this type of transformation:

const result = blinq(doc)
  .groupBy(c => c.car)
  .select(g => ({
    car: g.key,
    prices: g
      .selectMany(c => c.prices)
      .distinct()
      .toArray(),
    models: g.select(c => c.model).toArray()
  }))
  .toArray();

const doc = [{
    "car": "Ford",
    "prices": ["12", "3", "5", "1"],
    "model": "SUV"
  },
  {
    "car": "Ford",
    "prices": ["99", "88", "77"],
    "model": "T3"
  },
  {
    "car": "Toyota",
    "prices": ["33", "44", "55"],
    "model": "Subaru"
  },
  {
    "car": "Toyota",
    "prices": ["66", "50", "22"],
    "model": "Cheyenne"
  },
  {
    "car": "Peugeot",
    "prices": ["1", "2", "3"],
    "model": "503"
  }
];

const {
  blinq
} = window.blinq

const result = blinq(doc)
  .groupBy(c => c.car)
  .select(g => ({
    car: g.key,
    prices: g
      .selectMany(c => c.prices)
      .distinct()
      .toArray(),
    models: g.select(c => c.model).toArray()
  }))
  .toArray();
console.log(result)
<script src="https://cdn.jsdelivr.net/npm/blinq"></script>

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

The functionality of the Regions plugin in wavesurfer.js appears to be completely nonfunctional

I've been attempting to utilize the Regions plugin from wavesurfer.js, but unfortunately, it's not functioning as expected. Despite trying various methods suggested on different websites, I have yet to achieve success. Below is the snippet of c ...

Use PHP and jQuery to convert HTML to JSON from a specified URL and generate a tree view of the HTML elements

When a URL is entered into a textbox and the "OK" button is clicked, the left side of the page displays a preview of the HTML while the right side shows a tree view of the HTML tags (body, header, div, span, etc.) as shown in the attached image. The expect ...

Tips on implementing two ng-repeat directives within a specific element

Inside a JSON file, there is an array that needs to be iterated within <td> tags. The functionality entails creating a table based on user input, which includes the number of rows, input columns, and output columns provided by the user. Three arrays ...

`Problem encountered in establishing a database table through jQuery ajax`

I am completely new to utilizing jQuery and ajax. Currently, I am experimenting with creating a table on my local MySQL server using a JavaScript file that sends SQL statements to a .php file for execution. Here is the code in the .js file: function exec ...

create hyperlinks based on div clicks in HTML using JavaScript

Hey there! I'm working on a cool animation for my page that involves a star fade effect. After the animation, I want to open a link to another page on my site. Imagine I have 3 cards on my page, and when I click on any of them, I want the same animat ...

Clicking on a radio button can trigger the selection of another radio button

I'm currently working on a form that includes 8 radio buttons - 4 for System A and 4 for System B. The options for the buttons are CF, ISO, ISO-B, and NW. My goal is to create a functionality where selecting a radio button in System A automatically se ...

Duplicate the identical data retrieval query, this time utilizing a JavaScript Ajax post method

To enhance the data request query, implement a JavaScript Ajax post method to avoid page refresh when the button is pressed. This will allow for requesting another page and displaying it in a designated section on the webpage. Here's the code snippet ...

Zoom feature available on various images

My current setup includes one main image and multiple thumbnails that can be clicked to change the main image. The issue I encountered was when using jqzoom on the main image, the zoomed image would go blank after changing. After researching on stack overf ...

Expansive menu that stretches the full height of the webpage

I'm having difficulty making my side spry menu extend the full length of the webpage. I tried using this code: $("nav").css({ "height" : $("nav").height() }); but it still isn't working as expected. I just want the grey color, like ...

What is the best method for uploading a JSON file to a React web application and retrieving the file's link?

Is there a way to upload a JSON file to my React application and obtain the link to that file? Our app developer is working on implementing app linking and has requested this functionality. ...

Deselect the DOM element

Here is a jQuery code snippet: $(document).ready(function () { $(".story-area > h1, .story-area > p, .story-area > div > p").text(function () { return convertString($(this).text()); }); }); Additionally, there is a function de ...

An item was shown on the HTML page

Having some trouble displaying the graph generated by my R function on the opencpu server. Instead of the desired plot, all I see is [object Object] in the HTML page. Below is the snippet of code from my AngularJS controller: var req = ocpu.rpc("plotGraph ...

Encountered an error when attempting to extend the array function: Uncaught TypeError - Object [object Array] does not contain a 'max' method

Hello, I am currently attempting to integrate this function into my code: Array.getMaximum = function (array) { return Math.max.apply(Math, array); }; Array.getMinimum = function (array) { return Math.min.apply(Math, array); }; This is inspired ...

execute php sql after a certain delay

Currently, I am working with PHP, SQL, and JavaScript to develop a friend request system. In this system, if User-1 sends a friend request to User-2, User-2 must accept the request within 1 hour. If not, the request will be automatically denied or removed. ...

Can we save javascript-generated HTML audio as a file on the back-end server?

In my latest project, I am building a JavaScript sequencer that controls HTML audio using intervals and timeouts. The goal is to handle all the processing and recording on the back-end while displaying a "Processing..." message to the user, and then utili ...

scope.$digest completes before triggering scope.$watch in Karma unit tests

I am interested in testing this specific directive: .directive('uniqueDirective', function () { return { restrict: 'A', scope: { uniqueDirective: '@', tooltip: '@', placement: '@&apo ...

Tips for controlling frustum in three.js

Recently, I came across a fascinating parallax view implementation that creates an illusion of depth, and now I'm eager to recreate something similar using Three.js. One hurdle I've encountered is the need for a non-symmetric camera frustum. Ess ...

What is the best way to transfer information between two HTML pages using PHP?

While working on updating a record, I encountered an issue trying to pass the student's ID from one page to another without displaying it in the query string. Despite attempting to use window.location and AJAX for navigation between pages, I haven&apo ...

Using axiosjs to send FormData from a Node.js environment

I am facing an issue with making the post request correctly using Flightaware's API, which requires form data. Since Node does not support form data, I decided to import form-data from this link. Here is how my code looks like with axios. import { Fl ...

What is the best way to ensure that cleanup is always executed at the conclusion of a function

Imagine a scenario where I have the following function (psuedo-code) : function Foo() { let varThatNeedsCleanup = //something if(condition1) { return Error1; } if(condition2) { return Error2; } if(condition3) { return Error3; ...