Javascript: group JSON objects using specific key - javascript

I have the following JSON object and wanted to merge them by OrderID, making the items into array of objects:
[
{
"OrderID":"999123",
"ItemCode":"TED-072",
"ItemQuantity":"1",
"ItemPrice":"74.95",
},
{
"OrderID":"999123",
"ItemCode":"DY-FBBO",
"ItemQuantity":"2",
"ItemName":"DOIY Foosball Bottle Opener > Red",
"ItemPrice":"34.95",
}
]
and I'm wondering how in Javascript to merge the items on the same order...like this:
[{
"OrderID": "999123",
"Items": [{
"ItemCode": "DY-FBBO",
"ItemQuantity": "2",
"ItemName": "DOIY Foosball Bottle Opener > Red",
"ItemPrice": "34.95"
}, {
"ItemCode": "TED-072",
"ItemQuantity": "1",
"ItemName": "Ted Baker Womens Manicure Set",
"ItemPrice": "74.95"
}]
}]

I suggest you use javascript library like underscorejs/lazyjs/lodash to solve this kind of thing.
Here is the example on using underscorejs:
var data = [{
"OrderID":"999123",
"ItemCode":"TED-072",
"ItemQuantity":"1",
"ItemPrice":"74.95",
}, {
"OrderID":"999123",
"ItemCode":"DY-FBBO",
"ItemQuantity":"2",
"ItemName":"DOIY Foosball Bottle Opener > Red",
"ItemPrice":"34.95",
}]
var result = _.chain(data).groupBy(function (e) {
return e.OrderID;
}).map(function (val, key) {
return {
OrderID: key,
Items: _.map(val, function (eachItem) {
delete eachItem.OrderID;
return eachItem;
})
};
}).value();
Working example:
var data = [{
"OrderID":"999123",
"ItemCode":"TED-072",
"ItemQuantity":"1",
"ItemPrice":"74.95",
}, {
"OrderID":"999123",
"ItemCode":"DY-FBBO",
"ItemQuantity":"2",
"ItemName":"DOIY Foosball Bottle Opener > Red",
"ItemPrice":"34.95",
}];
var result = _.chain(data).groupBy(function (e) {
return e.OrderID;
}).map(function (val, key) {
return {
OrderID: key,
Items: _.map(val, function (eachItem) {
delete eachItem.OrderID;
return eachItem;
})
};
}).value();
document.write(JSON.stringify(result));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

This should do what you want it to do, but it's rather a group function than a merge function :)
You can see the result in the browser console.
var items = [
{
"OrderID":"999123",
"ItemCode":"TED-072",
"ItemQuantity":"1",
"ItemPrice":"74.95",
},
{
"OrderID":"999123",
"ItemCode":"DY-FBBO",
"ItemQuantity":"2",
"ItemName":"DOIY Foosball Bottle Opener > Red",
"ItemPrice":"34.95",
}
];
function groupBy(ungrouped, groupByProperty) {
var result = [],
getGroup = function (arr, val, groupByProperty) {
var result, j, jlen;
for (j = 0, jlen = arr.length; j < jlen; j++) {
if (arr[j][groupByProperty] === val) {
result = arr[j];
break;
}
}
if (!result) {
result = {};
result.items = [];
result[groupByProperty] = val;
arr.push(result);
}
return result;
}, i, len, item;
for (i = 0, len = ungrouped.length; i < len; i++) {
item = getGroup(result, ungrouped[i][groupByProperty], groupByProperty);
delete ungrouped[i][groupByProperty];
item.items.push(ungrouped[i]);
}
return result;
}
var grouped = groupBy(items, 'OrderID');
document.getElementById('result').innerHTML = JSON.stringify(grouped);
console.log(grouped);
<div id="result"></div>

Lodash is a great Javascript Utility library that can help you in this case. Include the latest version of lodash in your code and group the objects like this:
var mergedOrders = _.groupBy(OriginalOrders, 'OrderID');

It seems you'll have to do a function that, for each entry, will check if it match
try this :
// your array is oldArr
var newArr = []
for (var i=0;i<oldArr.length;i++){
var found = false;
for(var j=0;j<newArr.length;j++){
if(oldArr[i]["OrderID"]==newArr[j]["OrderID"]){
newArr[j]["Items"].push(oldArr[i]);
found=true;
break;
}
if(!found){
newArr.push({"OrderID" : oldArr[i]["OrderID"], "Items" : oldArr[i]});
}
}

You need to loop and create new grouped objects according to your requirement.
For an easier approach I would suggest using jquery-linq
var qOrderIds = $.Enumerable.From(myArray).Select(function(item) { return item.OrderID; }).Distinct();
var groupedList = qOrderIds.Select(function(orderId) {
return {
OrderID: orderId,
Items : $.Enumerable.From(myArray).Where(function(item) { item.OrderID === orderId}).ToArray()
};
}).ToArray();

Thank you for all your answers.
I was able to attain my goal (maybe a bit dirty and not as beautiful as yours but it worked on my end). Hoping this might help others in the future:
function processJsonObj2(dataObj, cfg) {
var retVal = dataObj.reduce(function(x, y, i, array) {
if (x[cfg.colOrderId] === y[cfg.colOrderId]) {
var orderId = x[cfg.colOrderId];
var addressee = x[cfg.colAddressee];
var company = x[cfg.colCompany];
var addr1 = x[cfg.colAddress1];
var addr2 = x[cfg.colAddress2];
var suburb = x[cfg.colSuburb];
var state = x[cfg.colState];
var postcode = x[cfg.colPostcode];
var country = x[cfg.colCountry];
var orderMsg = x[cfg.colOrderMessage];
var carrier = x[cfg.colCarrier];
delete x[cfg.colOrderId];
delete y[cfg.colOrderId];
delete x[cfg.colAddressee];
delete y[cfg.colAddressee];
delete x[cfg.colCompany];
delete y[cfg.colCompany];
delete x[cfg.colAddress1];
delete y[cfg.colAddress1];
delete x[cfg.colAddress2];
delete y[cfg.colAddress2];
delete x[cfg.colSuburb];
delete y[cfg.colSuburb];
delete x[cfg.colState];
delete y[cfg.colState];
delete x[cfg.colPostcode];
delete y[cfg.colPostcode];
delete x[cfg.colCountry];
delete y[cfg.colCountry];
delete x[cfg.colOrderMessage];
delete y[cfg.colOrderMessage];
delete x[cfg.colCarrier];
delete y[cfg.colCarrier];
var orderObj = {};
orderObj[cfg.colOrderId] = orderId;
orderObj[cfg.colAddressee] = addressee;
orderObj[cfg.colCompany] = company;
orderObj[cfg.colAddress1] = addr1;
orderObj[cfg.colAddress2] = addr2;
orderObj[cfg.colSuburb] = suburb;
orderObj[cfg.colState] = state;
orderObj[cfg.colPostcode] = postcode;
orderObj[cfg.colCountry] = country;
orderObj[cfg.colOrderMessage] = orderMsg;
orderObj[cfg.colCarrier] = carrier;
orderObj["Items"] = [ x, y ];
return orderObj;
} else {
var orderId = x[cfg.colOrderId];
var addressee = x[cfg.colAddressee];
var company = x[cfg.colCompany];
var addr1 = x[cfg.colAddress1];
var addr2 = x[cfg.colAddress2];
var suburb = x[cfg.colSuburb];
var state = x[cfg.colState];
var postcode = x[cfg.colPostcode];
var country = x[cfg.colCountry];
var orderMsg = x[cfg.colOrderMessage];
var carrier = x[cfg.colCarrier];
var itemCode = x[cfg.colItemCode];
var itemQuantity = x[cfg.colItemQuantity];
var itemName = x[cfg.colItemName];
var itemPrice = x[cfg.colitemPrice];
var item = {};
item[cfg.colItemCode] = itemCode;
item[cfg.colItemQuantity] = itemQuantity;
item[cfg.colItemName] = itemName;
item[cfg.colItemPrice] = itemPrice;
var orderObj = {};
orderObj[cfg.colOrderId] = orderId;
orderObj[cfg.colAddressee] = addressee;
orderObj[cfg.colCompany] = company;
orderObj[cfg.colAddress1] = addr1;
orderObj[cfg.colAddress2] = addr2;
orderObj[cfg.colSuburb] = suburb;
orderObj[cfg.colState] = state;
orderObj[cfg.colPostcode] = postcode;
orderObj[cfg.colCountry] = country;
orderObj[cfg.colOrderMessage] = orderMsg;
orderObj[cfg.colCarrier] = carrier;
orderObj["Items"] = [ item ];
return orderObj;
}
});
return retVal;
}

Related

Sum Values in Object

I am trying to sum values from a report in GoogleAdsScript.
The report has to be segmented by campaignName, because of filter criteria.
The results should show aggregated values for IDs that exist in multiple campaigns.
I have managed to transform the report into an array and group by ID.
The last step would be to sum the values for each ID, as the GroupBy function I am using is not doing this.
Here's what I got so far:
function main() {
var report = generateReport();
Logger.log(groupBy(reportArray, "Id"));
}
function generateReport() {
var report;
var accountSelector = MccApp.accounts()
.withIds(['123-456-7890']);
var accountIterator = accountSelector.get();
while (accountIterator.hasNext()) {
var account = accountIterator.next();
MccApp.select(account);
report = AdsApp.report('SELECT segments.product_item_id, metrics.cost_micros, metrics.conversions_value, campaign.name, metrics.conversions, segments.product_custom_attribute4, segments.product_custom_attribute3, segments.product_custom_attribute2, segments.product_custom_attribute1 FROM shopping_performance_view WHERE campaign.name REGEXP_MATCH ".*_PPF_.*" AND campaign.name NOT REGEXP_MATCH ".*_PPF_Y.*" AND metrics.cost_micros > 50000000 AND segments.date DURING LAST_30_DAYS ORDER BY segments.product_item_id ASC');
}
return report;
}
function formatMicros(value) {
const micros = parseFloat(value / 1000000).toFixed(2);
return `${micros}`;
}
var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
function reportToArray (report){
var array = [];
var rows = report.rows();
while (rows.hasNext()) {
//Relevante Variablen erstellen
var row = rows.next();
var campaignName = row["campaign.name"];
var offerId = row["segments.product_item_id"];
var conversionValue = row["metrics.conversions_value"];
var cost = formatMicros(row["metrics.cost_micros"]);
var conversions = row["metrics.conversions"];
var rowObject = {Kampagne:campaignName, Id:offerId, ConversionValue:conversionValue, Cost:cost, Converisons:conversions};
array.push(rowObject);
}
return array;
}
The result from the Logger.log look like this if the IDs are only present in one campaign:
{12345=[{Kampagne=SampleCampaignName1, Id=12345, Cost=84.68, Converisons=2.365506, ConversionValue=101.07449979}],
23456=[{Kampagne=SampleCampaignName1, Converisons=15.14796, Id=23456, ConversionValue=730.58781899, Cost=120.72}],
34567=[{ConversionValue=1185.87613113, Cost=108.33, Kampagne=SampleCampaignName1, Id=34567, Converisons=7.782904}]
And like this, if they are present in multiple campaigns:
45678=[{Kampagne=samplecampaignName1, Converisons=0.0, ConversionValue=0.0, Id=45678, Cost=65.73}, {ConversionValue=2091.72, Cost=77.34, Converisons=4.0, Id=45678, Kampagne=samplecampaignName2}]
How do I sum the values for Cost/ConversionValue/Conversions in this second Case?
Any help is greatly appreciated.
Kind Regards,
Jan
Sorry if I misunderstood the task.
var newArr = [];
class Kampagne {
constructor(Id, ConversionValue, Converisons, Cost) {
this.Id = Id;
this.ConversionValue = ConversionValue;
this.Converisons = Converisons;
this.Cost = Cost;
}};
var array = [
{Kampagne:'samplecampaignName1', Converisons:3.0, ConversionValue:0.0, Id:257680, Cost:65.73},
{ConversionValue:2091.72, Cost:77.34, Converisons:4.0, Id:257680, Kampagne:'samplecampaignName2'},
{ConversionValue:100, Cost:32.04, Converisons:1.0, Id:257681, Kampagne:'samplecampaignName3'}
];
array.forEach(function(element, idx){
let res = newArr.find((e) => e.Id == element.Id);
if(res==undefined) {
newArr.push(new Kampagne(element.Id, element.ConversionValue, element.Converisons, element.Cost));
} else {
res.ConversionValue += element.ConversionValue;
res.Converisons += element.Converisons;
res.Cost += element.Cost;
}
});
console.log(newArr);

How To Create Multiple Arrays From a Single Array?

I getting form data in my console like this:
{item[0][sku]: 'EC1000-WMK', item[0][qty]: '1', item[1][sku]: 'POP-11', item[1][qty]: '1', form_key: 'ZuQxqBMHmidjUxEt'}
form_key: "ZuQxqBMHmidjUxEt"
item[0][qty]: "1"
item[0][sku]: "EC1000-WMK"
item[1][qty]: "1"
item[1][sku]: "POP-11"
This is how the above data created:
$.fn.getFormData = function(){
var data = {};
var dataArray = $(this).serializeArray();
console.log(data);
console.log(dataArray);
for(var i=0;i<dataArray.length;i++){
console.log(dataArray);
data[dataArray[i].name] = dataArray[i].value;
}
return data;
}
but I want to make it like:
[
{ "sku": "EC1000-WMK", "qty": "1" }
{ "sku": "POP-11", "qty": "1" }
]
Use Input fields name be like
<input name="item.0.sku" />
<input name="item.0.qty" />
<input name="item.1.sku" />
<input name="item.2.qty" />
& then use this function
Here is the function which converts all form inputs to JSON format
const jsonSerialize = ($this) => {
$this = $this.find('input, select');
let data = {};
for (let i = 0; i < $this.length; i++) {
let el = $this[i];
let val = el.value;
if (!val) val = "";
let fullName = el.getAttribute("name");
if (!fullName) continue;
let fullNameParts = fullName.split('.');
let prefix = '';
let stack = data;
for (let k = 0; k < fullNameParts.length - 1; k++) {
prefix = fullNameParts[k];
if (!stack[prefix]) {
stack[prefix] = {};
}
stack = stack[prefix];
}
prefix = fullNameParts[fullNameParts.length - 1];
if (stack[prefix]) {
let newVal = stack[prefix] + ',' + val;
stack[prefix] += newVal;
} else {
stack[prefix] = val;
}
}
return data
}
let $form = $('form');
params = jsonSerialize($form)
Hope may this work for you

How to change csv to json array using javascript

I want to add an external CSV file into a JOSN Array in my JS Code.
I tried lots of codes, with no luck like this:
var map = {};
var rows = csv.split(/\n/g);
var keys = rows.shift().split(",");
rows.forEach(raw_row => {
var row = {};
var row_key;
var columns = raw_row.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);
columns.forEach((column, index) => {
var key = keys[index];
if (!key) return;
if (key === 'Name') {
row_key = column;
return;
}
if (key === "Coordinates") {
column = column.replace(/""/g, '"');
column = column.substring(1, column.length - 1);
column = column.replace(/([a-zA-Z_]+):/g, `"$1":`);
try {
column = JSON.parse(`{${column}}`);
} catch (e) {}
}
row[key] = column;
});
map[row_key] = row;
});
console.log(map);
but I believe my expectation is something else, so I dont get what I want.
could some one pleae help me to change this csv(file):
contry;fromNr;toNr;Type;cust_1;cust_2
US;0;100;wood;max;nuk
DE;100;500;metal;max;pal
into JSON Array:
[{
"country": "US",
"fromNr": 0,
"toNr": 100,
"Type": "wood",
"cust_1": "max",
"cust_2": "nuk"
}, {
"country": "DE",
"fromNr": 100,
"toNr": 500,
"Type": "metal",
"cust_1": "max"
}]
You can use the below function csvIntoJson to convert.
const csv = 'contry;fromNr;toNr;Type;cust_1;cust_2\nUS;0;100;wood;max;nuk\nDE;100;500;metal;max;pal';
const csvIntoJson = (csv, separator) => {
let [headers, ...rows] = csv.split('\n');
headers = headers.split(separator);
rows = rows.map(row => row.split(separator));
return rows.reduce((jsonArray, row) => {
const item = row.reduce((item, value, index) => {
return {...item, [headers[index]]: value};
}, {});
return jsonArray.concat(item);
}, []);
};
const jsonArray = csvIntoJson(csv, ';');
My suggestion use a library, But you still want to understand how it can be done then here is the simple code.
I have used ',' delimiter, You can change it to ';' or anything else as per your usecase.
steps:
Read csv as text
split text by new line to get rows
split row by delimiter like ',' or ';'
Do your stuff
code:
function Upload(input){
console.log("uploading");
let file = input.files[0];
let reader = new FileReader();
reader.readAsText(file);
reader.onload = function() {
map_object = [];
console.log(reader.result);
var textByLine = (reader.result).split("\n")
console.log(textByLine);
// read header
header = (textByLine[0]).split(',');
// read data
for(var i = 1 ; i< textByLine.length -1; i++){
temp_row = {}
row_data = textByLine[i].split(',');
for (var j = 0 ; j< header.length; j++){
temp_row[header[j]] = row_data[j]
}
console.log(temp_row);
map_object.push(temp_row);
}
console.log(map_object);
document.write(JSON.stringify(map_object));
};
reader.onerror = function() {
console.log(reader.error);
};
}
<input type="file" id="fileUpload" accept='.csv' onchange="Upload(this)"/>
var data = "contry;fromNr;toNr;Type;cust_1;cust_2\nUS;0;100;wood;max;nuk\nDE;100;500;metal;max;pal";
function CSVtoJSON(csv) {
var lines = csv.split("\n");
var result = [];
var headers = lines[0].split(";");
for (var i = 1; i < lines.length; i++) {
var obj = {};
var currentline = lines[i].split(";");
for (var j = 0; j < headers.length; j++) {
obj[headers[j]] = currentline[j];
}
result.push(obj);
}
return result;
}
console.log(CSVtoJSON(data));

JSON object changes properties

I'm developing a chrome extension, I have to iterate through a dictionary and transfer data from the objects that are in there to another objects, I store the last ones in an array, this problem happened. Here is the output: json_object_err Here is the desired output:
Here is my code:
var active_observers = {};
var participants_data = [];
function save_partcipants_data() {
var participant_data = {
name: "",
words: 0,
id: "",
positive_marks: 0
}
for (let el in active_observers) {
var finded = false;
participant_data.name = active_observers[el].user_name;
participant_data.words = Math.round(active_observers[el].speak_counter / 2.15);
participant_data.id = active_observers[el].user_id;
participant_data.positive_marks = active_observers[el].positive_marks;
for (let i in participants_data) {
if (participants_data[i].name === participant_data.name) {
participants_data[i].words += participant_data.words;
participants_data[i].positive_marks += participant_data.positive_marks;
finded = true;
console.log("object:");
console.log(participant_data);
console.log("list:");
console.log(participants_data);
}
}
if (!finded) {
participants_data.push(participant_data);
console.log("object:");
console.log(participant_data);
console.log("list:");
console.log(participants_data);
}
}
}
active_observers[user_id] = {
"user_name": user_name,
"user_id": user_id,
"speak_counter": 0,
"user_observer": observer,
"positive_marks": 0
};
var active_observers = {};
var participants_data = [];
save_partcipants_data();

change the json structure after getting data

I am getting a json data having structure
{
SearchDAO: [
{
PERSONADDRESS_H_ADDRESS_LINE_ONE: "599 Waterloo place",
PERSON_H_BIRTHDATE_VALUE: "1939-01-11 00:00:00",
PERSON_H_CREATE_TS: "2012-11-22 11:17:13.879",
PERSON_H_GENDER_CD: "M"
}
]
}
As you can see in the data set two type of keys are there
1. starting with "PERSONADDRESS"
2. starting with "PERSON"
I have to convert this structure to
{
"PERSON":[
{
H_BIRTHDATE_VALUE: "1939-01-11 00:00:00",
H_CREATE_TS: "2012-11-22 11:17:13.879",
H_GENDER_CD: "M"
}
],
"PERSONADDRESS":[
{
H_ADDRESS_LINE_ONE: "599 Waterloo place"
}
]
I am struggling to do this.
As It need to splice key string and change the structure
Please help
I am trying something like this
$.each(data.SearchDAO[0], function(k, v) {
var streetaddress= k.substr(0, k.indexOf('_'));
console.log(streetaddress)
if(returnVar[streetaddress] == undefined){
thisItem = [];
returnVar[streetaddress] = thisItem;
}
else {
thisItem = returnVar[streetaddress];
}
var obj = {};
obj.issueValue = v;
thisItem.push(obj);
});
console.log(thisItem)
I solved the problem
here is my code
returnVar={};
$.each(data.SearchDAO[0], function(k, v) {
var streetaddress= k.substr(0, k.indexOf('_'));
var keyFinal= k.substr(k.indexOf('_')+1,k.length-1);
console.log(keyFinal)
if(returnVar[streetaddress] == undefined){
thisItem = {};
returnVar[streetaddress] = thisItem;
thisItem[keyFinal]=v;
}
else {
thisItem = returnVar[streetaddress];
thisItem[keyFinal]=v;
}
});
console.log(returnVar)
This should do it (for multiple persons as well):
var json = {
SearchDAO: [
{
PERSONADDRESS_H_ADDRESS_LINE_ONE: "599 Waterloo place",
PERSON_H_BIRTHDATE_VALUE: "1939-01-11 00:00:00",
PERSON_H_CREATE_TS: "2012-11-22 11:17:13.879",
PERSON_H_GENDER_CD: "M"
},
{
PERSONADDRESS_H_ADDRESS_LINE_ONE: "123 Place",
PERSON_H_BIRTHDATE_VALUE: "1901-01-01 00:00:00",
PERSON_H_CREATE_TS: "2001-01-01 00:00:00.000",
PERSON_H_GENDER_CD: "F"
}
]
}
var converted = {};
for (var i = 0; i < json.SearchDAO.length; i++)
{
var row = json.SearchDAO[i];
var keys = Object.keys(row);
for (var j = 0; j < keys.length; j++)
{
var key = keys[j];
var key_prefix = key.substr(0, key.indexOf('_'));
var key_suffix = key.substr(key.indexOf('_') + 1);
if (!(key_prefix in converted)) converted[key_prefix] = [];
if (!(i in converted[key_prefix])) converted[key_prefix][i] = {};
converted[key_prefix][i][key_suffix] = row[key_prefix + "_" + key_suffix];
}
}

Categories