Combining JSON objects to form a new object within a JSON object using JavaScript

Here is the JSON data that I have:

{"rows":[
    {"shiftId":1,"shift":"Morning","item":"Tea","value":20},
    {"shiftId":1,"shift":"Morning","item":"Coffee","value":30},
    {"shiftId":2,"shift":"Evening","item":"Tea","value":40},
    {"shiftId":2,"shift":"Evening","item":"Coffee","value":35}
]}

I want to merge entries with the same shift, add their values together, and create a new object for each item. The desired output should look like this:

{"rows":[
    {
     "shiftId":1,
     "shift":"Morning",
     "item":[{"itemName":"Tea"},{"itemName":"Coffee"}],
     "value":50
     },
    {
    "shiftId":2,
    "shift":"Evening",
    "item":[{"itemName":"Tea"},{"itemName":"Coffee"}],
    "value":75
    }
]}

I attempted to achieve this using the following code:

var merged = {rows: []};
data.forEach(function (source) {
    if (!merged.rows.some(function (row) {
        return row.shiftId == source.shiftId;
    })) {
        merged.rows.push({
            shiftId: source.shift,
            shift: source.shift,
            item: [{
                itemName: source.shift
            }],
            value: source.value
        });
    } else {
        var existRow = merged.rows.filter(function (existRow) {
            return existRow.shiftId == source.shiftId
        })[0];
        existRow.total += source.total;  // There was an error here, it should be "existRow.value += source.value"
        existRow.item = source.item.push(existRow.item);  
    }
});

However, this code is not functioning as expected. Thank you in advance for your help.

Answer №1

A possible approach is to utilize a hash table to reference objects with the same shiftId, allowing for the creation of a new array containing the collected and grouped data.

var data = { rows: [{ shiftId: 1, shift: "Morning", item: "Tea", value: 20 }, { shiftId: 1, shift: "Morning", item: "Coffee", value: 30 }, { shiftId: 2, shift: "Evening", item: "Tea", value: 40 }, { shiftId: 2, shift: "Evening", item: "Coffee", value: 35 }] },
    result = {
        rows: data.rows.reduce(function (hash) {
            return function (r, a) {
                if (!hash[a.shiftId]) {
                    hash[a.shiftId] = { shiftId: a.shiftId, shift: a.shift, item: [], value: 0 };
                    r.push(hash[a.shiftId]);
                }
                hash[a.shiftId].item.push({ itemName: a.item });
                hash[a.shiftId].value += a.value;
                return r;
            };
        }(Object.create(null)), [])
    };

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Answer №2

To optimize your process, consider implementing a hash table:

var hashTable={};
var inputData={"rows":[
{"shiftId":1,"shift":"Morning","item":"Tea","value":20},
{"shiftId":1,"shift":"Morning","item":"Coffee","value":30},
{"shiftId":2,"shift":"Evening","item":"Tea","value":40},
{"shiftId":2,"shift":"Evening","item":"Coffee","value":35}
]}.rows;

inputData.forEach(function(data){
  var element=(hashTable[data.shiftId]=hashTable[data.shiftId]||{shiftId:data.shiftId,shift:data.shift,items:[],value:0});
   element.items.push({itemName:data.itemName});
   element.value+=data.value;
});

You can then generate the result as follows:

var resultingData={rows:[]};
for(key in hashTable){
 resultingData.rows.push(hashTable[key]);
}

Answer №3

Utilizing the power of Array.prototype.reduce()

const arrayItems = [{
        "shiftId": 1,
        "shift": "Morning",
        "item": "Tea",
        "value": 20
    },
    {
        "shiftId": 1,
        "shift": "Morning",
        "item": "Coffee",
        "value": 30
    },
    {
        "shiftId": 2,
        "shift": "Evening",
        "item": "Tea",
        "value": 40
    },
    {
        "shiftId": 2,
        "shift": "Evening",
        "item": "Coffee",
        "value": 35
    }
];

const newArray = arrayItems.reduce((accumulator, currentItem, index) => {
    if (!accumulator.length) { // Initial iteration
        accumulator.push(currentItem)
        return accumulator;
    }
    if (accumulator[accumulator.length - 1].shiftId === currentItem.shiftId) { // Check if current shiftId matches last shiftId
        if (!(accumulator[accumulator.length - 1].item instanceof Array)) {
            accumulator[accumulator.length - 1].item = [{ // Convert item to an array
                "itemName": accumulator[accumulator.length - 1].item
            }]
        }
        accumulator[accumulator.length - 1].item.push({ // Add current item name to the last item array
            "itemName": currentItem.item
        });
        accumulator[accumulator.length - 1].value = accumulator[accumulator.length - 1].value + currentItem.value // Value addition
    } else { // If new shiftId
        accumulator.push(currentItem);
    }
    return accumulator;
}, []);

console.log(newArray);

Answer №4

let data = {"rows":[
    {"shiftId":1,"shift":"Morning","item":"Tea","value":20},
    {"shiftId":1,"shift":"Morning","item":"Coffee","value":30},
    {"shiftId":2,"shift":"Evening","item":"Tea","value":40},
    {"shiftId":2,"shift":"Evening","item":"Coffee","value":35}
]};
let newData = {"rows":[]};

let lastShiftId = -1;
let newKey = -1;
for(key in data.rows){
  let currentShiftId = data.rows[key].shiftId;

  let obj = {"item":data.rows[key].item};
  if(lastShiftId != currentShiftId){
    newKey++;
    data.rows[key].item = [];
    newData.rows.push(data.rows[key]);    
  }

  newData.rows[newKey].item.push(obj);

  lastShiftId = currentShiftId;
}
console.log(newData.rows);

Fiddle: https://jsfiddle.net/t74ygy9L/

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 JQuery category filtering feature malfunctions when a category consists of more than two words

Utilizing Jquery, I have implemented a feature that displays project categories and allows users to filter projects based on the selected category. To view the code pen for this implementation, please click here: https://codepen.io/saintasia/pen/dzqZov H ...

Nuxt Js - Ensuring script is only loaded once during the initial page load

I already have a static website design, but now I'm converting it to Nuxt.js to make it more interactive. After running my Nuxt server with "npm run build...npm run start," the scripts load and my carousel/slides work fine. However, when I navigate to ...

Creating a method in Angular that combines async/await functionality with Observables

After transitioning from using async/await to Observables in Angular, I am trying to refactor the following code snippet to make it work with Observables: async refreshToken() { const headers = this.authStorage.getRequestHeader(); const body = { ...

how to execute Vue-Js method just one time

Is there a way to add a random number (ranging from 0 to the price of an item) to one of the data properties in Vue.js, but only once when the page is initially loaded? I am unable to use mounted and computed because I need to pass a parameter to the funct ...

Experiencing a lack of defined or no outcome when outputting the API callback

I am troubleshooting an issue with my script that searches for movie titles from a database. While I receive results in the console without any errors, the renderMovies function is not storing the API movie title, plot, and other details properly in my var ...

I encountered a TS error warning about a possible null value, despite already confirming that the value

In line 5 of the script, TypeScript raises an issue regarding the possibility of gameInstanceContext.gameInstance being null. Interestingly, this concern is not present in line 3. Given that I have verified its existence on line 1, it is perplexing as to w ...

Unable to decode JSON properly within iOS application

Hey there! I've been using NSJSONSerialization to decode JSON data from a web server for my iOS app, and it was working perfectly fine until recently. All of a sudden, the decoding process is only returning null values. I even tried hardcoding the JSO ...

In JavaScript, the "this" keyword points to a different object

Here is a script that needs attention: Bla = function() { this.prop = 123; } Bla.prototype.yay = function() { console.log(this,this.prop); } X = new Bla(); $(document).ready(X.yay); // output: #document undefined --> why? $(document).ready(functio ...

Issue with Angular Factory not being invoked

I am currently using a tutorial to create a MEAN app with Google Maps. However, I have encountered an issue where the map is not appearing on the page. Surprisingly, there are no errors in the browser console and even when debugging with node-inspector, I ...

Use the jQuery function `stop(true, true)` to swiftly end all animations currently in the queue

For handling animations in jQuery, I have been utilizing the stop(true, true) method to clear running animations so that the next one can start right away. What I observed was that while the first parameter, clearQueue, clears the entire animation queue, t ...

Is there a way to activate ng-class on only a single element?

In my code, I am using ng-repeat and ng-class for each element to select elements and add borders for the selected ones. <div class="main-block_channel_create"> <section class="parent_messageList cancelDelete"> <div id="section_animate" ...

Retrieve file server domain using JavaScript or jQuery

I'm trying to extract the domain name without the "http(s)://www." from a file link. For example, if the script returns "example.com", I want it to parse through links like "http://www.example.com/file.exe" or "https://example.com/folder/file.txt#some ...

`Manipulating the image source attribute upon clicking`

I need help changing the attr: { src: ...} binding of an img element when a different image is clicked. Here is an example: $(document).ready(function () { var viewModel = { list: ko.observableArray(), showRenderTimes: ...

Sharing information between pages in React through Router

I am struggling to transfer a single string from one page to another using react router and only functional components. I have created a button that links my pages, but I can't seem to pass the string successfully. Here is an example of the code on th ...

Tips on including variable in JSON data object

I am struggling with sending a JSON post in C# using variables instead of hardcoded values. Despite trying various methods, I have been unable to find a solution. The issue arises when attempting to extract the value stored in the 'num' variable ...

Navigating JSON with Java/Jackson

I am currently working on a Java application to parse JSON data from the Reddit API. The sample JSON data I am trying to parse is structured like this: [ { "kind": "Listing", "data": { "modhash": "1jq62oyvwe15aaba7eb18b0b4363b567a007507663 ...

Reactive forms in Angular now support changing focus when the Enter key is pressed

I have successfully created a table and a button that generates dynamic rows with inputs inside the table. One issue I'm facing is that when I press enter in the first input, a new row is created (which works), but I can't seem to focus on the ne ...

Is there a way for me to automatically go back to the home page when I press the back button on the browser?

My ecommerce website has a shopping cart page where customers can purchase products and make payments. After the payment is completed, they are directed to a thank you page. The flow of the website is as follows: Home page => Products => Shopping cart => ...

The function is missing a closing return statement and the return type does not specify 'undefined'

It seems like the function lacks an ending return statement and the return type does not include 'undefined'. In a recent refactoring of the async await function called getMarkets, I noticed that I had mistakenly set the return type as Promise: ...

The error message "node Unable to iterate over property 'forEach' because it is undefined" appeared

I am facing an error and unable to find the solution. I believe my code is correct. It is related to a video lesson where I attempt to display popular photos from Instagram using the Instagram API. However, when I try to execute it, I encounter this issue. ...