how to transform a source object into another object? - javascript

I am trying to transform an object or in other words I am trying change text of an object.
I have two object one is source and another is mapped object.using mapped object I want o transform the source object.
example
source object
{
"links": {
"Offering": {
"id":"offering-id",
"iconUrl": "",
"links": [
{
"text": "School",
"id":"school-id",
"onclickUrl": "https://www.school.com/school/"
},
{
"text": "happy",
"onclickUrl": "https://www.happy.com/help/",
"id":"happy-id"
}
]
},
"luck": {
"iconUrl": "",
"id":"hospital-id",
"links": [
{
"text": "Student",
"id":"student-id",
"onclickUrl": "https://www.student.com/school/"
}
]
}
}
}
mapped -object
let mappingObj = {
"hospital-id":"hospital-change",
"school-id":"school-change-xx",
"offering-id":"Offering-changes-map",
"happy-id":"happy-cs",
"student-id":"nnnnnn"
}
expectedout output
let expectedOutput = {
"links": {
"Offering-changes-map": {
"id":"offering-id",
"iconUrl": "",
"links": [
{
"text": "school-change-xx",
"id":"school-id",
"onclickUrl": "https://www.school.com/school/"
},
{
"text": "happy-cs",
"onclickUrl": "https://www.happy.com/help/",
"id":"happy-id"
}
]
},
"hospital-change": {
"iconUrl": "",
"id":"hospital-id",
"links": [
{
"text": "nnnnnn",
"id":"student-id",
"onclickUrl": "https://www.student.com/school/"
}
]
}
}
}
I have id's in source obj same id's are present in mapped obj.using this I want to change the text of all properties and keys.
I tried like that here is my whole code
https://jsbin.com/zaxoyineme/edit?js,console,output
let result = {};
function recursiveFn(Obj){
for(let i in Obj){
result[mappingObj[Obj[i].id] || i]=Obj[i];
if(typeof Obj[i]==="object"){
console.log('--obj--');
recursiveFn(Obj[i]);
}else if(Object.prototype.toString.call(Obj[i]) === '[object Array]'){
console.log('--Array--');
for(var k =0 ;k<Obj[i].length;k++){
Obj[i].text = result[mappingObj[Obj[i].id] || Obj[i].text]
}
}
}
}
for(let i in Obj){
result[mappingObj[Obj[i].id] || i]=Obj[i];
if(typeof Obj[i]==="object"){
console.log('----');
recursiveFn(Obj[i])
}else if(Object.prototype.toString.call(Obj[i]) === '[object Array]'){
console.log('--Array--');
for(var k =0 ;k<Obj[i].length;k++){
Obj[i].text = result[mappingObj[Obj[i].id] || Obj[i].text]
}
}
}
console.log(JSON.stringify(result))
I am using recession to get the expected output.but I am not able to get the expected output

Your code is way to complicated for what you are trying to do. From What I understood this should probably do your job.
let Obj = {
"links": {
"Offering": {
"id":"offering-id",
"iconUrl": "",
"links": [
{
"text": "School",
"id":"school-id",
"onclickUrl": "https://www.school.com/school/"
},
{
"text": "happy",
"onclickUrl": "https://www.happy.com/help/",
"id":"happy-id"
}
]
},
"luck": {
"iconUrl": "",
"id":"hospital-id",
"links": [
{
"text": "Student",
"id":"student-id",
"onclickUrl": "https://www.student.com/school/"
}
]
}
}
}
let mappingObj = {
"hospital-id":"hospital-change",
"school-id":"school-change-xx",
"offering-id":"Offering-changes-map",
"happy-id":"happy-cs",
"student-id":"nnnnnn"
}
// expected output
let expectedOutput = {
"links": {
"Offering-changes-map": {
"id":"offering-id",
"iconUrl": "",
"links": [
{
"text": "school-change-xx",
"id":"school-id",
"onclickUrl": "https://www.school.com/school/"
},
{
"text": "happy-cs",
"onclickUrl": "https://www.happy.com/help/",
"id":"happy-id"
}
]
},
"hospital-change": {
"iconUrl": "",
"id":"hospital-id",
"links": [
{
"text": "nnnnnn",
"id":"student-id",
"onclickUrl": "https://www.student.com/school/"
}
]
}
}
}
let result = {};
let midResult = {};
function updateObject (Obj) {
let i = 0;
let parseArray = Object.keys(Obj.links);
for (i =0; i < parseArray.length; i++) {
let id = parseArray[i]
let matchingId = mappingObj[Obj.links[id].id]
midResult[matchingId] = Object.assign({}, Obj.links[id])
}
}
updateObject(Obj);
result.links = Object.assign({}, midResult)
console.log(result)

Related

Replace key and strings in array in JSON

I have this JSON below:
{
"class": "List",
"list": [{
"name": "HandsUp"
"schedule": {
"type": "probability",
"theme": "Regular",
"occurance": {
"next": 1607687249008.9834,
"prev": null
}
}
}, {
"name": "Listing",
"waitingScreenInfo": {
"__class": "WaitingScreenInfo",
"getRecapTime": 1607687753.7949834
},
"schedule": {
"type": "Waiting2",
"theme": "Listing",
"occurance": {
"next": 1607687249008.9834,
"prev": null
}
}
}
]
}
and I have this one:
{
"HandsUp": "HandsDown",
"Listing": "ImgList",
"Waiting2": "UpNDown"
}
The equivalent of the strings in the first JSON are in the second JSON and I wonder how can I make a function that finds the equivalents of the strings in the first JSON and then replace all of them even though if there is more than one?
You can do this
Go through the array
check if property name equals the key from your "repl" object
if yes reassign the value with the one in your "repl" object
let stru = {
"class": "List",
"list": [{
"name": "HandsUp",
"schedule": {
"type": "probability",
"theme": "Regular",
"occurance": {
"next": 1607687249008.9834,
"prev": null
}
}
}, {
"name": "Listing",
"waitingScreenInfo": {
"__class": "WaitingScreenInfo",
"getRecapTime": 1607687753.7949834
},
"schedule": {
"type": "Waiting2",
"theme": "Listing",
"occurance": {
"next": 1607687249008.9834,
"prev": null
}
}
}]
}
const repl = {
"HandsUp": "HandsDown",
"Listing": "ImgList",
"Waiting2": "UpNDown"
}
console.log("Before ", stru)
stru.list.forEach(element => {
// keys and values correspond at the index
let keys = Object.keys(repl);
let values = Object.values(repl);
for (let i = 0; i < keys.length; i++) {
if (keys[i] === element.name) {
element.name = values[i];
}
}
});
console.log("Afterwards ", stru)

Normalize JSON to a custom schema

I have an array of objects with the following format
var arr = [
{
"productId": "123456",
"productName": "Test Product 1",
"description": [
"This is delicious",
"Suitable for vegetarian"
],
"attributes": {
"internalId": "091283"
"category": "Dairy"
},
"order": 1
}
];
And I am trying to map into something like below
[
[{
{
"name": "productId",
"value": "123456"
},
{
"name": "productName",
"value": "Test Product 1"
},
{
"name": "description",
"value": ["This is delicious", "Suitable for vegetarian"]
},
{
"name": "attributes",
"value": {
{
"name": "internalId",
"value": "091283"
},
{
"name": "category",
"value": "Dairy"
}
}
},
{
"name": "order",
"value": 1
}
}]
]
I tried mapping simple properties before going further and now stuck at getting only the last property of each object in the loop.
Suppose I don't know what are the format of incoming data and how can I normalize the JSON object to the format I want?
normalizeJson = (array) => {
for(i = 0; i < array.length; i++){
normalizedJson[i] = {};
Object.keys(array[i]).forEach(key => {
if (array[i][key] && typeof array[i][key] === "object") {
// normalizeJson(obj[key]);
// console.log(key + ' is object');
return;
} else {
o = {};
o["name"] = key;
o["value"] = array[i][key];
normalizedJson[i] = o;
// normalizedJson[i]["name"] = key;
// normalizedJson[i].value = array[i][key];
// console.log(key);
return;
}
});
}
console.log(normalizedJson);
};
Or is there any library I can use in order to achieve this?
Try this
var obj = [
{
productId: "123456",
productName: "Test Product 1",
description: ["This is delicious", "Suitable for vegetarian"],
attributes: {
internalId: "091283",
category: "Dairy",
},
order: 1,
},
];
function normalizeObject(obj) {
var result = [];
if (Array.isArray(obj)) {
for (let i of obj) {
result.push(normalizeObject(i));
}
} else if (typeof obj == "object") {
for (let i of Object.keys(obj)) {
result.push({ name: i, value: normalizeObject(obj[i]) });
}
} else {
return obj;
}
return result;
}
console.log(JSON.stringify(normalizeObject(obj), null, 2));
This looping method called recursion. Which is loop by calling function itself.

Append a key value pair by copying the value of a specific key in javascript in nested json structure

I have a nested json structure like below
const data = {
"name": "A",
"invalid": {
"distinctCountOnColumns": [
{
"key": "some_key",
"value": 101557856
}
],
"groupByAndCountOnColumns": [
[
{
"key": "some_key",
"value": "no data",
"count": 101557856
}
],
]
},
"children": [
{
"name": "B",
"count": 1654164,
"children": [
{
"name": "B1",
"count": 16564,
},
{
"name": "B2",
"count": 165411,
}
]
},
{
"name": "C",
"count": 15135
}
]
}
I want to append a key called value next to the key count by copying the value of the key count. But the key count inside the object invalid should not be considered.
The resultant data is given below
const resultData = {
"name": "A",
"invalid": {
"distinctCountOnColumns": [
{
"key": "some_key",
"count": 192869,
"value": 101557856
}
],
"groupByAndCountOnColumns": [
[
{
"key": "some_key",
"value": "no data",
"count": 101557856
}
],
]
},
"children": [
{
"name": "B",
"count": 1654164,
"value": 1654164,
"children": [
{
"name": "B1",
"count": 16564,
"value": 16564
},
{
"name": "B2",
"count": 165411,
"value": 165411
}
]
},
{
"name": "C",
"count": 15135,
"value": 15135
}
]
}
I tried this method but the key value is not getting added next to the key count.
const deepCopy = (arr) => {
let copy = [];
arr.forEach(elem => {
if(Array.isArray(elem)){
copy.push(deepCopy(elem))
}else{
if (typeof elem === 'object') {
copy.push(deepCopyObject(elem))
} else {
copy.push(elem)
}
}
})
return copy;
};
const deepCopyObject = (obj) => {
let tempObj = {};
for (let [key, value] of Object.entries(obj)) {
if(key !== "invalid" && key === "count"){
obj.value = obj[key];
}
if (Array.isArray(value)) {
tempObj[key] = deepCopy(value);
} else {
if (typeof value === 'object') {
tempObj[key] = deepCopyObject(value);
} else {
tempObj[key] = value
}
}
}
return tempObj;
};
const resultData = deepCopyObject(data);
console.log("result", data)
You could create recursive function that takes data and old and new key do be added. It also checks if the some of the parent elements has the invalid key value at it ignores that object and its children.
const data = {"name":"A","invalid":{"distinctCountOnColumns":[{"key":"some_key","value":101557856}],"groupByAndCountOnColumns":[[{"key":"some_key","value":"no data","count":101557856}]]},"children":[{"name":"B","count":1654164,"children":[{"name":"B1","count":16564},{"name":"B2","count":165411}]},{"name":"C","count":15135}]}
function update(data, oldKey, newKey, isValid = true) {
if (oldKey in data && isValid) {
data[newKey] = data[oldKey]
}
for (let i in data) {
if (isValid) {
if (typeof data[i] == 'object') {
update(data[i], oldKey, newKey, isValid && i !== 'invalid')
}
}
}
}
update(data, 'count', 'value')
console.log(data)

Convert flat data to hierarchical with inner objects javascript

I faced with common issue converting simple flat data to hierarchical. I have found multiple topics about that but still can't get how to convert flat data exactly to necessary me hierarchical format
this my json
[
{
"id": 1,
"name": "Sponsor",
"description": null,
"parentId": null
},
{
"id": 2,
"name": "Class",
"description": null,
"parentId": 1
},
{
"id": 3,
"name": "Study",
"description": null,
"parentId": 2
},
{
"id": 4,
"name": "Site",
"description": null,
"parentId": 3
}
]
and I need to get format like this
[
{
"data":{
"id": 1,
"name":"Sponsor",
"description":null,
"parentId":"null"
},
"children":[
{
"data":{
"id": 2,
"name":"Class",
"description":null,
"parentId":"1"
},
"children":[
{
"data":{
"id": 3,
"name":"Study",
"description":null,
"parentId":"2"
},
"children": [
{
"data":{
"id": 4,
"name":"Site",
"description":null,
"parentId":"3"
}
}
]
}
]
}
]
}
]
this is my function
flatToHierarchy(flat) {
let roots = [];
let all = {};
flat.forEach(function (item) {
all[item.id] = item
});
Object.keys(all).forEach(function (id) {
let item = all[id];
if (item.parentId === null) {
roots.push(item)
} else if (item.parentId in all) {
let p = all[item.parentId];
if (!('Children' in p)) {
p.children = []
}
p.children.push(item)
}
});
console.log(roots);
return roots
}
output
[
{
"id": 1,
"name": "Sponsor",
"description": null,
"parentId": null,
"children": [
{
"id": 2,
"name": "Class",
"description": "Together",
"parentId": 1,
"children": [
{
"id": 3,
"name": "Study",
"description": "browsing data",
"parentId": 2,
"children": [
{
"id": 4,
"name": "Site",
"description": null,
"parentId": 3,
"children": []
}
]
}
]
}
]
}
]
I'm pretty close to desire result. Could somebody to help me fix that ?
Edited
the right answer provided by #Someone3
this is slightly modified code for my needs
flatToHierarchy (flat) {
let roots = [];
let all = {};
let ids = [];
flat.forEach(function (item) {
let itemId = item.id;
let convertedItem = function (id) {
let newItem = {};
newItem['data'] = id;
return newItem;
} ;
all[itemId] = convertedItem(item);
ids.push(itemId);
});
for (let i = 0; i < ids.length; i++) {
let id = ids[i];
let convertedItem = all[id];
let parentId = convertedItem.data.parentId;
if (parentId === null) {
roots.push(convertedItem);
} else if (parentId in all) {
let p = all[parentId];
if (!('children' in p)) {
p.children = []
}
p.children.push(convertedItem)
}
}
return roots
}
The code below is full source code for your situation. I modified and added a few lines from your source code.
Note that this code assumes that parents are always inserted to this tree before their children do. If this assumption is not always true then your code need to be changed more than this.
let flatData = [
{
"id": 1,
"name": "Sponsor",
"description": null,
"parentId": null
},
{
"id": 2,
"name": "Class",
"description": null,
"parentId": 1
},
{
"id": 3,
"name": "Study",
"description": null,
"parentId": 2
},
{
"id": 4,
"name": "Site",
"description": null,
"parentId": 3
}
];
function convertItem(item) {
let newItem = {};
newItem.data = item;
return newItem;
}
function flatToHierarchy(flat) {
let roots = [];
let all = {};
let ids = [];
flat.forEach(function (item) {
let itemId = item.id;
let convertedItem = convertItem(item);
all[itemId] = convertedItem;
ids.push(itemId);
});
// We use ids array instead of object to maintain its previous order.
for (let i = 0; i < ids.length; i++) {
let id = ids[i];
let convertedItem = all[id];
let parentId = convertedItem.data.parentId;
if (parentId === null) {
delete convertedItem.data.parentId;
delete convertedItem.data.id;
roots.push(convertedItem);
} else if (parentId in all) {
let p = all[parentId];
if (!('Children' in p)) {
p.children = []
}
delete convertedItem.data.parentId;
delete convertedItem.data.id;
p.children.push(convertedItem)
}
};
console.log(roots);
return roots
}
flatToHierarchy(flatData);
We can factor out two deletes before push.
How about my way?
function flatToHierarchy (flatData) {
const tree = JSON.parse(JSON.stringify(flatData)) // or using `cloneDeep` of lodash library to not side-effect with flatData
tree.forEach((item) => {
item.children = tree.filter((element) => element.parent_id === dept.id)
});
const roots = tree.filter((item) => item.parent_id === 0)
return roots
}
const flatToHierarchy = (inputArr, parent = null) => {
const result = [];
for(let i = 0; i<inputArr.length; i++) {
if(inputArr[i].parentId === parent) {
const dataObj = {
data : {
...inputArr[i],
}
}
const children = flatToHierarchy(inputArr, inputArr[i].id);
if(children.length > 0) {
dataObj.children = children;
}
result.push(dataObj);
}
}
return result;
}

How to iterate nested json object?

I have a nested JSON Object and i want to iterate that.
JSON Response
{
"specifications": {
"IP6": {
"name": "Devices",
"productSubType": "Device",
"productSpecificationType": "Phones"
}
},
"offers": {
"US-PRE-IPHONE-CASE": {
"path": "productDetails/IP6",
"familyData": {
"0": "Missing Family Level data Should be here"
},
"facets": [],
"type": [],
"offers": {
"US-PRE-HG-PH-IP6": {
"hashDigest": "cf23df2207d99a74fbe169e3eba035e633b65d94",
"offerName": "offerNameString",
"productName": "iPhone 6 Case Mate Naked Tough Case - Clear",
"productOfferings": {
"ratings": "4.5",
"noOfReviews": "2010"
},
"offerStatus": {},
"displayPriority": "100200",
"descriptions": {
"shortDescription": "Iphone Decription ",
"longDescription": "longDescriptionStri6 descriptionng",
"alternativeDescription": "alternativeDescriptionString",
"reprsentativeDescription": ""
},
"specifications": [
"someSpecificationId1"
],
"brand": "Apple",
"productType": "Device",
"productSubType": "Phone",
"offerType": "",
"offerSubType": "",
"compatibility": {},
"classification": [],
"images": {
"thumbanail": {
"imagePath": "http://s.tmocache.com/images/png/products/accessories/SUPM43270/SUPM43270-small.png"
}
},
"equipmentCharacteristics": {},
"offerVariants": {},
"type": "hard-good",
"offers": [],
"family": "IP6",
"pricePoints": {
"withServicePrice16GBNEW": {
"displayPriority": "1001",
"pricingMessage": "device price with service activation",
"price": "34.99",
"discounts": {}
}
},
"dynamicPricingData": {},
"inventoryData": {
"SKUGOLD16GBN": {
"availibility": "Pre-order now!",
"availableTimeline": ""
}
}
}
}
}
}
}
Now as you see there are nested JSON objects in this and I want the value of
productName
shortDescription
imagePath
availibility
What I have tried is
function change(){
var acc = response; //response is JSON Object mentioned above
var accArray = [];
var accArray1 = [];
for (var obj in acc.specifications){
accArray.push(obj);
}
alert(accArray[0]);
for (var obj in accArray[0].offers){
accArray1.push(obj);
}
alert(accArray1[0]);
}
I am able to get the first object the first alert output is
IP6
but when I am trying to iterarte the IP6 object in same way the output is
undefined
I want to fetch all the 4 values as I mentioned above and then put them in an array.
As Grundy pointed out in his comment, obj in your code is the key of properties/items in specifications object. That means 'obj' is just a string.
To get reference to the object, change your code as below:
for(var obj in acc.specifications){
accArray.push(acc.specifications[obj]);
}
For better readability change obj to key
You can use for..in loop and recursion.
function find(obj, fieldName){
if(Array.isArray(obj)){
for(var i=0, len=obj.length;i<len;i++){
var nested = find(obj[i],fieldName);
if(nested.isFind) return nested;
}
}else{
if(typeof obj !== "object") return {isFind:false};
for(var i in obj){
if(i === fieldName) return {isFind:true, value:obj[i]};
var nested = find(obj[i],fieldName);
if(nested.isFind) return nested;
}
}
return {isFind:false};
}
this function return object with field isFind for case when available value can be null or undefined
var obj = {
"specifications": {
"IP6": {
"name": "Devices",
"productSubType": "Device",
"productSpecificationType": "Phones"
}
},
"offers": {
"US-PRE-IPHONE-CASE": {
"path": "productDetails/IP6",
"familyData": {
"0": "Missing Family Level data Should be here"
},
"facets": [],
"type": [],
"offers": {
"US-PRE-HG-PH-IP6": {
"hashDigest": "cf23df2207d99a74fbe169e3eba035e633b65d94",
"offerName": "offerNameString",
"productName": "iPhone 6 Case Mate Naked Tough Case - Clear",
"productOfferings": {
"ratings": "4.5",
"noOfReviews": "2010"
},
"offerStatus": {},
"displayPriority": "100200",
"descriptions": {
"shortDescription": "Iphone Decription ",
"longDescription": "longDescriptionStri6 descriptionng",
"alternativeDescription": "alternativeDescriptionString",
"reprsentativeDescription": ""
},
"specifications": [
"someSpecificationId1"
],
"brand": "Apple",
"productType": "Device",
"productSubType": "Phone",
"offerType": "",
"offerSubType": "",
"compatibility": {},
"classification": [],
"images": {
"thumbanail": {
"imagePath": "http://s.tmocache.com/images/png/products/accessories/SUPM43270/SUPM43270-small.png"
}
},
"equipmentCharacteristics": {},
"offerVariants": {},
"type": "hard-good",
"offers": [],
"family": "IP6",
"pricePoints": {
"withServicePrice16GBNEW": {
"displayPriority": "1001",
"pricingMessage": "device price with service activation",
"price": "34.99",
"discounts": {}
}
},
"dynamicPricingData": {},
"inventoryData": {
"SKUGOLD16GBN": {
"availibility": "Pre-order now!",
"availableTimeline": ""
}
}
}
}
}
}
}
function find(obj, fieldName){
if(Array.isArray(obj)){
for(var i=0, len=obj.length;i<len;i++){
var nested = find(obj[i],fieldName);
if(nested.isFind) return nested;
}
}else{
if(typeof obj !== "object") return {isFind:false};
for(var i in obj){
if(i === fieldName) return {isFind:true, value:obj[i]};
var nested = find(obj[i],fieldName);
if(nested.isFind) return nested;
}
}
return {isFind:false};
}
var result = ['productName','shortDescription','imagePath','availibility'].map(function(el){ return find(obj,el).value});
document.getElementById('r').innerHTML = JSON.stringify(result,null,2);
<pre id='r'></pre>
Your json code is a complex data binding structure. It same like c# complex data binding. So you need to call the obj by through it call name.
for eg:
var data = {"ex":{"a":{"a1":"a1","a2":"a2"},"b":{"b1":"b1","b2":"b2"}}}
so data is a class and it includes "ex" object
data returns =>Object {ex: Object}
if you need to access "a" or "b" object means , you need to access through the"ex" object.
for eg:
data.ex.a => Object {a1: "a1", a2: "a2"}
in your code
for(var obj in acc.specifications){
accArray.push(obj);
}
obj only push 1st element of acc.sppectification object.
So please try this.
foreach(var obj acc.specification){
arr1.push(acc.specification[obj])
}
foreach (var obj acc.offers){
arr2.push(acc.offers[obj])
}

Categories