I have an array imported via AJAX.
I want to create a new array based on the original one and scan through the whole new array in order to clean the value WHATEVER the key associated to it.
The imported dataset looks like this:
[
{id:"1", color:"red_blue", height:"100_200" },
{id:"2", color:"green", height:"100_20" },
{id:"3", color:"orange_yellow", height:"50" }
]
And the jQuery process looks like this
dataSet = JSON.parse(response);
// create a new array based on the imported array
var row = 0;
$.each(dataSet, function(key, value) {
cleanDataSet.push(dataSet[row]);
row++;
});
// clean the new array
var row = 0;
// Go through each row of the array
$.each(cleanDataSet, function(key, value) {
// Go through each key and value of this array
$.each(cleanDataSet[row], function(key, value) {
var myVariable = thisValueWhateverTheKey.split('_');
// if a split is detected in the value
if (myVariable[1]) {
// Update the value
thisValueWhateverTheKey = myVariable[0];
}
row++;
});
});
console.log(cleanDataSet)
The "thisValueWhateverTheKey" part is obviously the one I can't figure out.
It's easy when I target the values of a specific key (I would use "value.nameofmykey" but not that much when I target any value of any key. "value" alone won't work.
You can use value directly, most probably you're geting confused by using key, value in both loops. Also note that you're splitting on double underscore __ which needs to be a single one _ as per your data.
Here's how you can simplify:
$.each(cleanDataSet, function(index, cleanDataSetRow){
// Go through each key and value of this array
$.each(cleanDataSetRow, function(key, value){
var myVariable = value.split('_');
// if a split is detected in the value
if(myVariable[1]){
// Update the value
cleanDataSetRow[key] = myVariable[0];
}
});
});
I think your code/question is a little confusing - if I understand it properly you are wanting something like this. Note the map function creates a new array populated with the results of calling a provided function on every element in the calling array. e.g.
const data = [{
id: "1",
color: "red_blue",
height: "100_200"
},
{
id: "2",
color: "green",
height: "100_20"
},
{
id: "3",
color: "orange_yellow",
height: "50"
}
]
const clean = data.map(x => {
// x is each object in the original array
// i.e. data[0], data[1], etc
for (y in x) {
// y is each property in the object
// e.g. data[0]["id"], data[0]["color"], etc
// so here we are setting the value of each property of each object
x[y] = x[y].split('_')[0]
}
// finally return each modified object
return x;
})
// so clean is a new array based on data
// where each property has been set to the correct value
console.log(clean)
If this isn't correct could you possibly edit your question to included and example of how you want the data to look - i.e. before/after.
const data = [
{
id: "1",
color: "red_blue",
height: "100_200"
},
{
id: "2",
color: "green",
height: "100_20"
},
{
id: "3",
color: "orange_yellow",
height: "50"
}
];
var clean = data.map(item => Object.fromEntries(
Object.keys(item).map(key => [key, item[key].split('_')[0]])
));
console.log(clean);
When you iterate through each object use Object.entries() and destruct each entry (ex. [key, value]):
...
Object.entries(obj).forEach(([key, val]) => {
if (val === value) {
obj[key] = ''
}
...
let data = [
{id:"1", color:"red_blue", height:"100_200" },
{id:"2", color:"green", height:"100_20" },
{id:"3", color:"orange_yellow", height:"50" }
];
function removeValue(objectArray, value) {
objectArray.forEach(obj => {
Object.entries(obj).forEach(([key, val]) => {
if (val === value) {
obj[key] = '';
}
});
});
return objectArray;
}
console.log(removeValue(data, "100_20"));
console.log(removeValue(data, "orange_yellow"));
Related
I have an API that response JSON data like this-
{
"unitcode":"apple",
"description":"bus",
"color":"red",
"intent":"Name 1"
}
I want to change like this-
{
"Value1":"apple",
"Value2":"bus",
"value3":"red",
"value4":"sale"
}
Presently, I can code to rename single key but i want some code to replace all key in one shot. my code like this-
request(baseurl)
.then( body => {
var unit = JSON.parse(body);
unit.intent = "sales"
unit.value1 = unit.unitcode
delete unit.unitcode;
console.log(unit)
console.log(unit.Value1)
var unit2 = JSON.stringify(unit)
// let code = unit.description;
conv.ask('Sales is 1 million metric tonnes ' + unit2);
})
please help me out on this and please little elaborate also to learn something new. thanks
Create a Map of original key to new key (transformMap). Convert the object to pairs of [key, value] with Object.entries(), iterate with Array.map() and replace the replacement key from the Map (or the original if not found). Convert back to an object with Object.toEntries():
const transformMap = new Map([
['unitcode', 'Value1'],
['description', 'Value2'],
['color', 'Value3'],
['intent', 'Value4']
]);
const transformKeys = obj =>
Object.fromEntries(
Object.entries(obj)
.map(([k, v]) => [transformMap.get(k) || k, v])
);
const obj = {
"unitcode": "apple",
"description": "bus",
"color": "red",
"intent": "Name 1"
};
const result = transformKeys(obj)
console.log(result)
If you know the object structure and it is constant, you could just use destructing like so.
const data = {
"unitcode":"apple",
"description":"bus",
"color":"red",
"intent":"Name 1"
};
// If the object is fixed and the fields are known.
const mapData = ({ unitcode, description, color, intent }) => ({
Value1: unitcode,
Value2: description,
Value3: color,
Value4: intent
});
console.log(JSON.stringify(mapData(data)));
But if the object has an unknown number of properties:
const data = {
"unitcode":"apple",
"description":"bus",
"color":"red",
"intent":"Name 1"
};
// If the object is fixed and the fields are known.
const mapData = (data) => {
return Object.keys(data).reduce((a,v,i) => {
a[`Value${i+1}`] = data[v];
return a;
}, {});
};
console.log(JSON.stringify(mapData(data)));
You can edit the array to have the values you need
let i=0,j=0,unit1={};
let unit = JSON.parse(body);
let unit3=["val1","val2","val3","val4"]
let unit5=Object.values(unit);
for(let key in unit){
unit1[unit3[i++]]=unit5[j++];
}
var unit2 = JSON.stringify(unit1)
console.log('Sales is 1 million metric tonnes \n' + unit2);
//Sales is 1 million metric tonnes
//{"val1":"apple","val2":"bus","val3":"red","val4":"Name 1"}
Well your target is to modify the keys and retain the value
In that context, you can iterate through your data. To dynamically generate keys as Value1, Value2, etc, we will append Value with iteration index which is going to be unique always.
const modifyInput = (input) => {
const modifiedInput = {}
Object.values(input).forEach((item, index) => {
modifiedInput[`Value${index + 1}`] = item
})
return modifiedInput
}
Use this function, pass your input and get your desired result
I have a JSON object with the structure as below
const inputObj = {
"prop1": "val1",
"prop2": {
"prop2_1": "val2_1",
"prop2_2": "val2_2"
}
"prop3": "val3"
}
My objective: I would like to take the property, including the nested property, and store the result in a txt file, but not in JSON format. To make it clear, here is my expected output in the txt file:
{
prop1: {
id: 'prop1'
},
prop2_prop2_1: {
id: 'prop2.prop2_1'
},
prop2_prop2_2: {
id: 'prop2.prop2_2'
}
prop3: {
id: 'prop3'
}
}
So far, I could write the non nested property, but still not in the structure which I expected. Here is the result so far:
{
"prop1": "prop1",
"prop3": "prop3"
}
Its still in JSON format, not in the structure that I expected, and the nested property still not caught (I still thinking how to get it)
here is the code so far to make my current result:
const fs = require('fs')
const fileName = "./results.txt"
function getAllKeys(obj, path = [], result = []) {
Object.entries(obj).forEach(([k, v]) => {
if (typeof v === 'object') getAllKeys(v, path.concat(k), result)
else result.push(path.concat(k).join("."))
})
return result
}
const inputToFile = getAllKeys(inputObj)
// console.log(inputToFile)
// result of the console.log
// prop1
// prop2.prop2_1
// prop2.prop2_2
// prop3
const newObj = {}
for (var i = 0; i < inputToFile.length; i++) {
var input = inputToFile[i]
var dotIndex = input.indexOf('.') // to check if its from the nested JSON property of the inputObj
if (dotIndex === -1) {
// no dot or nested property in the JSON
newObj[input] = input.toString()
} else {
// if the input contain dot, which is a nested JSON
}
}
fs.writeFileSync(fileName, JSON.stringfy(newObj))
// if I use above line, the result in the file is as I had mention above. But, if the code is like below:
const finals = JSON.stringfy(newObj)
fs.writeFileSync(fileName, JSON.parse(finals))
// the output in the file is only "[Object object]" without double quote
Update
The reason why I need the result to be formatted like that, is because I want to use react-intl. I already have the locale file (the translation), which looks like the inputObj (the structure). Then, I need to make a file, which like this (below), so the lib could translate it:
import { defineMessages } from 'react-intl';
const MessagesId = defineMessages({
prop1: {
id: 'prop1'
},
prop2_prop2_1: {
id: 'prop2.prop2_1'
},
prop2_prop2_2: {
id: 'prop2.prop2_2'
},
prop3: {
id: 'prop3'
}
})
export default MessagesId;
Thats why, I need it to be not like JSON. Because I already have thousand codes for the translation, but need to define it in the MessagesId. It would be so much takes time rite if I do it manually .__.
Ps: the react-intl is works, the problem is only the converting as my initial questions
This script can handle multiple levels of nestied object.
const outputObj = {};
const convertNestedObj = (obj, parentKey = []) => {
for (key in obj) {
newParentKey = [...parentKey, key];
if (typeof obj[key] === 'object') {
convertNestedObj(obj[key], newParentKey);
} else {
outputObj[newParentKey.join('_')] = { id: newParentKey.join('_') };
}
}
};
convertNestedObj(inputObj);
How to add uniqueId field in below JSON. This array has large number of data and needs to dynamic unique identifier on existing array.
[{"title":"Accompanying"},{"title":"Chamber music"},{"title":"Church
music"}......]
so, this should look as follow:
[{"title":"Accompanying", "uniqueId": 1},{"title":"Chamber music", "uniqueId": 2}..]
uniqueId- type, number or guid.
Note: don't know the "title" or what other fields could be, so, could not map the fields by name.
I would go for a simple for loop
let myArray = [{"title":"Accompanying"},{"title":"Chamber music"},{"title":"Church music"}];
let i = 0, ln = myArray.length;
for (i;i<ln;i++){
myArray[i].uniqueId = i+1;
}
console.log(myArray);
If this is a one time thing you could do the following:
const newArray = oldArray.map((x, i) => ({
// If the object is dynamic you can spread it out here and add the ID
...x,
// Use the items index in the array as a unique key
uniqueId: i,
}));
If you want to use a guid generator instead (I'd recommend that) just replace i with whatever you use to generate a GUID and ensure that any time you add to the collection you generate a new GUID for the data.
const newArray = oldArray.map((x) => ({ ...x, uniqueId: generateGuid() }));
const yourDynamicObjects = [
{
title: 'A title',
author: 'A. Author'
},
{
foo: 'bar',
},
{
quotient: 2,
irrational: Math.sqrt(2)
}
];
const updatedData = yourDynamicObjects.map((x, i) => ({ ...x, uniqueId: i, }));
console.log(updatedData);
You can use map & in it's call back function use the index parameter to create uniqueId
item.title is not known actually as its dynamic array and so, could
not map with particular field names
In this case use Object.keys to get an array of all the keys . Then loop over it and add the key to a new object
let k = [{
"title": "Accompanying"
}, {
"title": "Chamber music"
}, {
"title": "Church"
}]
let getArrayKey = Object.keys(k[0]);
let n = k.map(function(item, index) {
let obj = {};
getArrayKey.forEach(function(elem) {
obj[elem] = item[elem];
})
obj.uniqueId = index + 1
return obj;
});
console.log(n)
Also you can use spread operator
let k = [{
"title": "Accompanying"
}, {
"title": "Chamber music"
}, {
"title": "Church"
}]
let n = k.map(function(item, index) {
return Object.assign({}, { ...item,
uniqueId: index + 1
})
});
console.log(n)
I have a basic json question that is giving me headache since a couple of hours, I am trying to dynamically add keys to a Json object using an array of string.
Here is my array of string:
let key = ['session', 'view_state', 'footer', 'config', 'items']
I have another variable which is jsonValue and is my whole json object. I want to end up with one of those options:
jsonValue.session.view_state.footer.config.items
jsonValue['session']['view_state']['footer']['config']['items']
This is my best attempt using a forEach.
forEach(jsonKeys, (el) => {
jsonCollection += jsonCollection !== undefined ? '."' +[el + '"'] : [ '"' + el + '"' ];
})
But I have this result:
undefined"session"."view_state"."footer"."config"."items"
Any help will be appreciated!
To get a value using the keys array
Iterate with Array#reduce, check the type of the current value, if it's an object, return the value of the key, if not return undefined:
const obj = {
"demo": true,
"session": {
"view_state": {
"footer": {
"config": {
"items": [
1,
2
]
}
}
}
}
};
const keys = ['session', 'view_state', 'footer', 'config', 'items'];
const value = keys.reduce((val, key) => val && typeof val === 'object' ?
val[key] : undefind, obj);
console.log(value);
To add a value using the keys array
Use Array#reduceRight to create a chain of objects with the value you want. Use Object#assign to update the original object with the results:
const keys = ['session', 'view_state', 'footer', 'config', 'items'];
const obj = { demo: true };
Object.assign(obj, keys.reduceRight((val, key) => ({ [key]: val }), [1, 2])); // replace [1, 2] with the actual items
console.log(obj);
I am working with a JSON object which can have a property ids at any leaf. I want to traverse the object and find all of the instances of the ids property and store each id in a collection.
Mocked up JSON Object (the ids property could be at much deeper property locations).
{
"id": "b38a683d-3fb6-408f-9ef6-f4b853ed1193",
"foo": {
"ids": [
{
"id": "bd0bf3bd-d6b9-4706-bfcb-9c867e47b881"
},
{
"id": "d1cc529d-d5d2-4460-b2bb-acf24a7c5999"
},
{
"id": "b68d0c8c-548e-472f-9b01-f25d4b199a71"
}
],
"baz": "super"
},
"bar": {
"ids": [
{
"id": "bd0bf3bd-d6b9-4706-bfcb-9c867e47b881"
},
{
"id": "d1cc529d-d5d2-4460-b2bb-acf24a7c5999"
},
{
"id": "b68d0c8c-548e-472f-9b01-f25d4b199a71"
}
]
}
}
I am using the following code to traverse the above JSON.
var jsonFile = require('./file_test.json'); // the above in my local directory
function traverse(obj, ids) {
for (var prop in obj) {
if (typeof obj[prop] == "object" && obj[prop]) {
if (prop == 'ids') {
for (var i = obj[prop].length - 1; i >= 0; i--) {
ids.push(obj[prop][i]._id);
};
}
traverse(obj[prop], ids);
}
}
}
var ids = new Array();
traverse(jsonFile, ids);
console.log('ids', ids);
The above nets the following:
ids
[
'b68d0c8c-548e-472f-9b01-f25d4b199a71',
'd1cc529d-d5d2-4460-b2bb-acf24a7c5999',
'bd0bf3bd-d6b9-4706-bfcb-9c867e47b881',
'b68d0c8c-548e-472f-9b01-f25d4b199a71',
'd1cc529d-d5d2-4460-b2bb-acf24a7c5999',
'bd0bf3bd-d6b9-4706-bfcb-9c867e47b881'
]
While my code works I am not convinced that I am doing this the most efficient or best way. Is there a better way to find all instances of the ids property? Perhaps without passing in an array but returning one? Or setting up for a callback with an ids array?
If the data was actually a JSON string, and not a JavaScript object, you could have something like:
// assuming `json` is the data string
var ids = [];
var data = JSON.parse(json, function(key, value) {
if (key === "id")
ids.push(value);
return value;
});
See reviver on JSON.parse method.
what you have is fine, but this is a little shorter and uses the .map function:
var jsonFile = require('./file_test.json'); // the above in my local directory
function traverse(obj) {
var ids = [];
for (var prop in obj) {
if (typeof obj[prop] == "object" && obj[prop]) {
if (prop == 'ids') {
ids = obj[prop].map(function(elem){
return elem.id;
})
}
ids =ids.concat(traverse(obj[prop]));
}
}
return ids;
}
var ids =traverse(jsonFile);
console.log('ids', ids);
What you're basically trying to do is a tree search of this JSON object, am I right? So if we assume that ids is always a leaf then we do not need to traverse those nodes as we know they are at the leaf and will contain what we want.
Change the if {...} traverse to if {...} else {traverse}
If it is possible to change the data structure of ids to a list of strings instead of a list of objects then you will be able to save the iteration over the array and just merge it onto the ids array passed in, but it depends completely on the context and whether or not you can make this change!
Sorry I'm not of more help!
Assuming ES5 is available natively or via a shim:
function gimmeIds(obj) {
return Object.keys(obj||{})
.reduce(function(ids, key) {
if(key === 'ids') {
return ids.concat(obj[key].map(function(idObj) {
return idObj.id;
}));
}
if(obj[key] && typeof obj[key] == 'object') {
return ids.concat(gimmeIds(obj[key]));
}
return ids;
}, []);
}
Using object-scan this becomes very simple. Note that you can easily specify what is targeted (in this case **.ids[*].id)
// const objectScan = require('object-scan');
const data = { id: 'b38a683d-3fb6-408f-9ef6-f4b853ed1193', foo: { ids: [{ id: 'bd0bf3bd-d6b9-4706-bfcb-9c867e47b881' }, { id: 'd1cc529d-d5d2-4460-b2bb-acf24a7c5999' }, { id: 'b68d0c8c-548e-472f-9b01-f25d4b199a71' }], baz: 'super' }, bar: { ids: [{ id: 'bd0bf3bd-d6b9-4706-bfcb-9c867e47b881' }, { id: 'd1cc529d-d5d2-4460-b2bb-acf24a7c5999' }, { id: 'b68d0c8c-548e-472f-9b01-f25d4b199a71' }] } };
const findIds = (input) => objectScan(['**.ids[*].id'], { rtn: 'value' })(input);
console.log(findIds(data));
/* => [ 'b68d0c8c-548e-472f-9b01-f25d4b199a71',
'd1cc529d-d5d2-4460-b2bb-acf24a7c5999',
'bd0bf3bd-d6b9-4706-bfcb-9c867e47b881',
'b68d0c8c-548e-472f-9b01-f25d4b199a71',
'd1cc529d-d5d2-4460-b2bb-acf24a7c5999',
'bd0bf3bd-d6b9-4706-bfcb-9c867e47b881' ]
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.7.1"></script>
Disclaimer: I'm the author of object-scan