Build key value array from nested JSON - javascript

I have the following JSON object. I need to convert it in javascript into a one-level associative array. (key-value pairs) I've written a recursive function but can't seem to get it to work the way I want it to. Kindly refer to the example below for what I've written:
{
"Title" : "Test Match",
"Players" : [
{
"ID" : 1,
"Name" : "Ma Couella",
"Results" : [2,2,0],
"TeamMates" : [
{
"ID" : 2,
"Age" : 24,
"LikesToWin" : false
}
]
}, {
"ID" : 22,
"Name" : "Shawn Kato",
"Results" : [2,1,0],
"TeamMates" : [
{
"Name" : "Gerald Anderson",
"Age" : 24,
"LikesToWin" : false
}
]
}
],
"Referees" : [
{
"ID" : 10,
"Name" : "Janice Tieu",
"YearsAsReferee" : 10,
"EmploymentHistory" : [
{
"JobTitle" : "Senior Referee",
"YearsOnTheJob" : 20,
"FavouriteMatchesRefereeed" : [
{
"Title" : "Duran vs Leonard 1",
"Year" : 1992,
"Description" : "I was refereeing the test match but I put on make up so Duran lost the bout."
}, {
"Title" : "Duran vs Leonard 2",
"Year" : 1994,
"Description" : "I was refereeing the second match but I put on make up so Duran lost another bout."
}
]
}, {
"JobTitle" : "Juniour Refereee",
"YearsOnTheJob" : 3,
"FavouriteMatchesRefereeed" : [
{
"Title" : "Mexican Figher Jones vs Anna Himley",
"Year" : 1972,
"Description" : "I coached this match. Hehe."
}, {
"Title" : "Jennifer from the block 2",
"Year" : 1982,
"Description" : "I coached this other match. Hehe."
}
]
}
]
}
]
}
Example of expected associative array below:
[
"Title" => "Test Match",
"Players[0][ID]" => 0,
// rest of the array...
"Players[0][Teammates][0][ID]" => 2,
// rest of the array...
"Referees[0][EmploymentHistory][FavouriteMatchesRefereeed][Title]" => "Duran vs Leonard 1"
]
Here is what I've done so far (javascript)
function converJSONToStrings(values, prevParent){
console.log(values);
var result = [];
for (var key in values)
{
var value = values[key];
if(value.constructor === Array) {
// console.log("Found object array in key", key );
for(var x = 0; x<value.length; x++){
result[key + '[' + x + ']'] = converJSONToStrings(value[x]);
}
} else if (typeof value == 'object') {
for(var x in value){
result[key + '[' + x + ']'] = converJSONToStrings(value[x]);
}
} else {
result[key] = value;
}
}
return result;
}

Finally came up with a solution! Code below...
/**
* Formats the JSON result to an associative array, concatenating child and parent keys
*/
var convertJSONAssoc = function(obj, firstlevel) {
// consider string, number and boolean values in JSON as the last
// elements and can't be recursed into any further
if (typeof obj == 'string' || typeof obj == 'number' || typeof obj == 'boolean') {
var ab = [];
var bc = {};
bc.key = '';
bc.val = obj;
ab.push(bc);
return ab;
}
// the top most call which builds the final result
if (firstlevel) {
var result = {};
for (key in obj) {
var val = obj[key];
var s = convertJSONAssoc(val, false);
for (var o = 0; o < s.length; o++) {
var v = s[o];
result[key + v['key']] = v['val'];
}
}
return result;
} else {
// this is where the recursion happens. As long as objects are found,
// we use the code below to keep on parsing obj keys
var paths = [];
for (var key in obj) {
var val = obj[key];
var s = convertJSONAssoc(val, false);
for (var o = 0; o < s.length; o++) {
var v = s[o];
var de = {};
de.key = "[" + key + "]" + v['key'];
de.val = v['val'];
paths.push(de);
}
}
return paths;
}
}

This is an old question that came back up because of edits from the OP. Modern techniques make this a bit easier than it was when the question was written.
This uses two functions. pathEntries I use to turn objects into a similar format that I find more useful, something like
[
[['Title'], 'Test Match'],
[['Players', 0, 'ID'], 1],
[['Players', 0, 'Name'], 'Ma Couella,
// ...
[['Referees', 0, 'EmploymentHistory', 1, 'FavouriteMatchesRefereeed', 1, 'Year'], 1982],
[['Referees', 0, 'EmploymentHistory', 1, 'FavouriteMatchesRefereeed', 1, 'Description'], 'I coached this other match. Hehe.']
]
Then convert, with a combination of key mapping and Object.fromEntries (which is easy to shim if you need to support environments without it), turns this into your required format. It looks like this:
const pathEntries = (obj) =>
Object (obj) === obj
? Object .entries (obj) .flatMap (
([k, x]) => pathEntries (x) .map (([p, v]) => [[k, ... p], v])
)
: [[[], obj]]
const convert = (obj) =>
Object .fromEntries (
pathEntries (obj) .map (([k, v]) => [
k[0] + k .slice (1) .map (n => `[${n}]`) .join (''),
v
])
)
const data = {Title: "Test Match", Players: [{ID: 1, Name: "Ma Couella", Results: [2, 2, 0], TeamMates: [{ID: 2, Age: 24, LikesToWin: !1}]}, {ID: 22, Name: "Shawn Kato", Results: [2, 1, 0], TeamMates: [{Name: "Gerald Anderson", Age: 24, LikesToWin: !1}]}], Referees: [{ID: 10, Name: "Janice Tieu", YearsAsReferee: 10, EmploymentHistory: [{JobTitle: "Senior Referee", YearsOnTheJob: 20, FavouriteMatchesRefereeed: [{Title: "Duran vs Leonard 1", Year: 1992, Description: "I was refereeing the test match but I put on make up so Duran lost the bout."}, {Title: "Duran vs Leonard 2", Year: 1994, Description: "I was refereeing the second match but I put on make up so Duran lost another bout."}]}, {JobTitle: "Juniour Refereee", YearsOnTheJob: 3, FavouriteMatchesRefereeed: [{Title: "Mexican Figher Jones vs Anna Himley", Year: 1972, Description: "I coached this match. Hehe."}, {Title: "Jennifer from the block 2", Year: 1982, Description: "I coached this other match. Hehe."}]}]}]}
console .log (convert (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
Note that I often write pathEntries in terms of simpler getPaths and path functions. That is cleaner but less efficient as it requires extra traversals of the object.

Related

(Recursion) How to get all key/value pairs from an Object with nested objects and arrays

I have an object that look like this:
{
"id": 45745049
"seller": {
"first_name": "Sam",
"last_name": "Smith",
"email": "samsmith#smith.com",
"phone": {
"number": "1111-1111",
"verified": false
},
},
"order_items": [
{
"item": {
"id": "29239765",
"title": "item1",
"colors": [
"red",
"green",
"blue"
]
},
"quantity": 1,
"unit_price": 230,
},
{
"item": {
"id": "238457363",
"title": "item2",
"colors": [
"red"
]
},
"quantity": 2,
"unit_price": 110,
}
],
"date_created": "2020-08-03T12:17:25.000-04:00",
"date_last_updated": "2020-08-03T16:51:35.61Z"
}
I want an array with pairs of EVERY key in the object with the value.
For example:
[
["id", 45745049],
["first_name", "Sam"],
.....,
["phone.number", "1111-1111"],
["phone.verified", false],
....etc
]
Everything Ok until that point. The problem is when a property is an array of objects. The output I want is the following:
[
...,
["order_items1.item.id", 29239765],
["order_items1.item.colors1", "red"],
["order_items1.item.colors2", "green"],
...,
["order_items2.item.id", 238457363],
["order_items2.item.colors1", "red"],
...etc
]
So it needs to check if the property is an array and add the position number if so.
I know I need a recursive function but I dont know how to do it.
This is what I got until now.
getObjectKeys = (obj) => {
let FieldName = "";
let FieldValue = "";
for(var prop in obj) {
FieldName += prop;
if(!(prop instanceof Array) && (typeof prop !== "object") && obj[prop]) {
FieldValue = obj[prop];
} else if(prop instanceof Array && prop.length !== 0){
prop.forEach((innerItem, i) => {
FieldName += `${i+1}.`;
// check if the inner item is an array or whatever an do it all again
// Dont know what to do here.
});
} else {
getObjectKeys(obj[prop]);
}
}
return [FieldName, FieldValue];
}
Note: I dont want the empty or null keys.
I would be very grateful if someone can help me. Thanks anyways!
This does something very similar to what you're looking for. It's a technique I use often.
const getPaths = (obj) =>
Object (obj) === obj
? Object .entries (obj) .flatMap (([k, v]) => getPaths (v) .map (p => [k, ... p]))
: [[]]
const path = (ps) => (obj) =>
ps .reduce ((o, p) => (o || {}) [p], obj)
const flatten = (obj) =>
Object .fromEntries (getPaths (obj) .map (p => [p.join('.'), path (p) (obj)]))
const input = {id: 45745049, seller: {first_name: "Sam", last_name: "Smith", email: "samsmith#smith.com", phone: {number: "1111-1111", verified: false}}, order_items: [{item: {id: "29239765", title: "item1", colors: ["red", "green", "blue"]}, quantity: 1, unit_price: 230}, {item: {id: "238457363", title: "item2", colors: ["red"]}, quantity: 2, unit_price: 110}], date_created: "2020-08-03T12: 17: 25.000-04: 00", date_last_updated: "2020-08-03T16: 51: 35.61Z"}
console .log (flatten (input))
.as-console-wrapper {min-height: 100% !important; top: 0}
The differences are that there is a separator before the array index and that I use zero-based arrays, not one-based arrays.
I would suggest that it's a much better output format. If nothing else, it would probably allow you to rehydrate the original format. But if you want to change it, you should probably simply reduce the path to combine the numeric elements with their predecessors, something like:
const flatten = (obj) =>
Object .fromEntries (getPaths (obj) .map (p => [
p .reduce (
(a, k) => /^\d+$/ .test(k) ? [...a .slice (0, -1), a [a .length - 1] + (1 + (+k))] : [...a, k],
[]
) .join ('.'),
path2 (p) (obj)
]))
But this would require changes if the outer object might be an array.
Again, though, absent a very good reason to use your requested format, I would strongly recommend my alternative.

How to create a sub-associative object from a list of array keys in JavaScript?

I have an object from user input. The keys to that object are separated by commas, and I just want to separate those keys and make the keys of the object.
The key_array below is dynamic from user input, generates a different array each time, below I give you an example.
I have shown the object in my code which you can see below. you can also see the output by running that code.
var main_array = {};
var key_array = {
'user,name' : 'user name',
'user,email' : 'Email address',
'order,id' : 123456,
'order,qty' : 2,
'order,total' : 300,
'order,product,0,name' : "product1",
'order,product,0,qty' : 1,
'order,product,0,price' : 100,
'order,product,1,name' : "product2",
'order,product,1,qty' : 1,
'order,product,1,price' : 200,
};
for (keys in key_array){
var value = key_array[keys];
// What do I do here to get the output I want?
main_array['[' + keys.split(",").join('][')+ ']'] = value;
}
console.log(main_array);
Running the code above will give you the following output which is incorrect. And the output I don't want.
{
[order][id]: 123456,
[order][product][0][name]: "product1",
[order][product][0][price]: 100,
[order][product][0][qty]: 1,
[order][product][1][name]: "product2",
[order][product][1][price]: 200,
[order][product][1][qty]: 1,
[order][qty]: 2,
[order][total]: 300,
[user][email]: "Email address",
[user][name]: "user name"
}
I want an output like JSON below, so please tell me how to do it.
{
"user":{
"email" : "Email address",
"name" : "user name"
},
"order":{
"id" : 123456,
"qty" : 2,
"total" : 300,
"product":[
{
"name" : "product1",
"price" : 100,
"qty" : 1
},{
"name" : "product2",
"price" : 200,
"qty" : 1
}
]
}
}
Note: Please do not use eval, as using eval in this way is terribly unreliable, bad work and unsafe. Because I get all my data from user input, the likelihood of abuse can increase.
Use Object.entries to go over key and values of object.
Split the key by , separator and then build the object.
While building object, make sure to merge the keys and values using mergeTo method.
Then convert the objects which has the numerical keys then convert to object using convertObjsToArray method.
var key_array = {
"user,name": "user name",
"user,email": "Email address",
"order,id": 123456,
"order,qty": 2,
"order,total": 300,
"order,product,0,name": "product1",
"order,product,0,qty": 1,
"order,product,0,price": 100,
"order,product,1,name": "product2",
"order,product,1,qty": 1,
"order,product,1,price": 200
};
const mergeTo = (target, obj) => {
Object.entries(obj).forEach(([key, value]) => {
if (typeof value === "object" && !Array.isArray(value)) {
if (!target[key]) {
target[key] = {};
}
mergeTo(target[key], obj[key]);
} else {
target[key] = value;
}
});
};
const convertObjsToArray = obj => {
Object.entries(obj).forEach(([key, value]) => {
if (typeof value === "object") {
if (Object.keys(value).every(num => Number.isInteger(Number(num)))) {
obj[key] = Object.values(value);
} else {
convertObjsToArray(obj[key]);
}
}
});
};
const res = {};
Object.entries(key_array).map(([key, value]) => {
const keys = key.split(",");
let curr = { [keys.pop()]: value };
while (keys.length > 0) {
curr = { [keys.pop()]: curr };
}
mergeTo(res, curr);
});
convertObjsToArray(res);
console.log(res);
You can create the objects and keys required from the string dynamically, take each key and split it to an array using split(','). Using each item in the array create the structure required. Assuming if a key is a number, then it's parent must be an array.
Object.keys(key_array).forEach(key => {
const path = key.split(',');
let current = main_array;
for (let i = 0; i < path.length - 1; i++) {
if (!current[path[i]]) {
current[path[i]] = path[i + 1] && !isNaN(path[i + 1]) ? [] : {};
}
current = current[path[i]];
}
current[path.pop()] = key_array[key];
});
console.log(main_array); // Desired result

Filtering array of object using key in Javascript (node.js)

Please anyone can help, I want to filter data based on key in node.js, I've tried most of things, but didn't worked.
Below example data which needs to be filtered. I could able to filter key:value pair, nested Json object but filtering Array of json object is not working.
E.g. var data =
[{
"createdBy":"Tom"
"logistics" : 0,
"paymentStatus" : "Paid",
"orderAmount" : 5393.75,
"details" : {
"street": "S.S road",
"postCOde": "440111",
},
"subOrders" : [
{
"name" : "sub Product1",
"mrp" : 12,
"details": "desk"
},
{
"name" : "subProduct2",
"mrp" : 89,
"details": "chair"
}
]
}]
result object should be filtered based on given permission array
var permissionArray = ['logistics','paymentStatus','details.street','subOrders.name','subOrders.details'];
filtered result should look like
{
result = [{
"logistics" : 0,
"paymentStatus" : "Paid",
"details" : {
"street": "S.S road",
},
"subOrders" : [
{
"name" : "sub Product1",
"details" : "desk"
},
{
"name" : "sub Product1",
"details" : "chair"
}
]
}]
}
Building on #radulle's answer to allow the 'details.name' dot notation desired:
(Also updated to now allow multiple subfields of one field - like 'subOrders.name' and 'subOrders.details')
var arr =
[{
"createdBy":"Tom",
"logistics" : 0,
"paymentStatus" : "Paid",
"orderAmount" : 5393.75,
"details" : {
"street": "S.S road",
"postCode": "440111"
},
"subOrders" : [
{
"name" : "sub Product1",
"mrp" : 12,
"details": "desk"
},
{
"name" : "subProduct2",
"mrp" : 89,
"details": "chair"
}
]
}]
var permissionArray = ['logistics','paymentStatus','details.street', 'details.postCode','subOrders.name', 'subOrders.details'];
var arrFiltered = arr.map(el => {
let newEl = {}
for (let elm of permissionArray){
if (elm.includes('.')){
//console.log(elm);
const split_arr = elm.split('.')
//console.log(el[split_arr[0]]);
if (el[split_arr[0]] instanceof Array){
if (!newEl.hasOwnProperty([split_arr[0]]) ){
newEl[split_arr[0]] = el[split_arr[0]].map((child,index) => ({[split_arr[1]]: child[split_arr[1]]}) )
} else {
el[split_arr[0]].forEach((child,index) => {
//console.log(child[ split_arr[1] ]);
newEl[split_arr[0]][index][split_arr[1]] = child[split_arr[1]];
})
}
} else{
if (!newEl.hasOwnProperty([split_arr[0]]) ){
newEl[split_arr[0]] = {[split_arr[1]]: el[split_arr[0]][split_arr[1]]}
} else {
newEl[split_arr[0]][split_arr[1]] = el[split_arr[0]][split_arr[1]];
}
}
} else {
newEl[elm] = el[elm];
}
}
return newEl;
}
)
console.log(arrFiltered)
.as-console-wrapper { max-height: 100% !important; top: 0; }
NOTE: you need to check first if a dot is included with elm.includes('.'), then you have to split it into its two parts with elm.split('.'), then finally you need to check if the value of the key is an array, like 'subOrders' or if it is just an object like 'details' and handle each case with either directly calling the child key, or mapping over the array and calling the child key.
With the permission array as:
var permissionArray = ['logistics','paymentStatus','details.street', 'details.postCode','subOrders.name', 'subOrders.details'];
The output is:
[
{
"logistics": 0,
"paymentStatus": "Paid",
"details": {
"street": "S.S road",
"postCode": "440111"
},
"subOrders": [
{
"name": "sub Product1",
"details": "desk"
},
{
"name": "subProduct2",
"details": "chair"
}
]
}
]
NOTE: upon request of the OP, this now also allows you to have two subfields of one field like 'subOrders.name', 'subOrders.details'
For this !newEl.hasOwnProperty([split_arr[0]]) is used to check if the property/key doesn't already exist. If it does not, then create it, but if it does, then modify this existing property/key's value/item.
You could take a two step approach where you group same keys in an array and store the nested properties as well to the grouped parents.
This is important if you have same parent keys, like
['subOrders.name', 'subOrders.mrp']
For example a grouped array looks like this:
[
[
"logistics"
],
[
"paymentStatus"
],
[
"details",
["street"]
],
[
"subOrders",
["name", "mrp"]
]
]
Then build new objects based on the key and nested keys.
function filter(keys) {
var pathes = keys.reduce((r, path) => {
var [key, ...rest] = path.split('.'),
temp = r.find(([q]) => q === key);
if (rest.length)
if (temp) temp[1].push(rest.join('.'));
else r.push([key, [rest.join('.')]]);
else
if (!temp) r.push([key]);
return r;
}, []);
return function (object) {
const keys = pathes.filter(([key]) => key in object);
return Object.fromEntries(keys.map(([key, rest]) => [
key,
rest
? Array.isArray(object[key])
? object[key].map(filter(rest))
: filter(rest)(object[key])
: object[key]
]));
};
}
var permissionArray = ['foo', 'logistics', 'paymentStatus', 'details.street', 'subOrders.name'],
data = [{ createdBy: "Tom", logistics: 0, paymentStatus: "Paid", orderAmount: 5393.75, details: { street: "S.S road", postCOde: "440111", }, subOrders: [{ name: "sub Product1", mrp: 12 }, { name: "subProduct2", mrp: 89 }] }],
result = data.map(filter(permissionArray));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Instead of building a filtered output, we may operate on original obj and remove its props.
The permissions represent a tree (or trie if node is a word (. delimited))
If we further assume that any specified path is accessible in data, then any leaf has for parent an array or object (and so forth).
We then build a tree, and for any node traverse data and remove the keys which are not part of our specification.
const data = {"createdBy":"Tom","logistics":0,"paymentStatus":"Paid","orderAmount":5393.75,"details":{"street":"S.S road","postCOde":"440111"},"subOrders":[{"name":"sub Product1","mrp":12},{"name":"subProduct2","mrp":89}],"a":{"b":[{"c":3,"d":"a"},{"c":4,"e":"f"}]}}
const d = JSON.parse(JSON.stringify(data)) // do not mutate original
const v = ['logistics','paymentStatus','details.street','subOrders.name','subOrders.details','a.b.c']
const tree = v.map(x => x.split('.')).reduce((o, p) => {
p.reduce((c, x) => (c[x] = c[x] || {}), o)
return o
},{})
function rec (keep, node) {
if (Object.keys(keep).length === 0) return
if (Array.isArray(node)) { return node.forEach(rec.bind(0, keep)) }
for (const k in node) {
!(k in keep) ? delete node[k] : rec(keep[k], node[k])
}
}
rec(tree, d)
console.log(JSON.stringify(d,null,2))
You can maybe do it like this:
var arr =
[{
"createdBy":"Tom",
"logistics" : 0,
"paymentStatus" : "Paid",
"orderAmount" : 5393.75,
"details" : {
"street": "S.S road",
"postCOde": "440111"
},
"subOrders" : [
{
"name" : "sub Product1",
"mrp" : 12
},
{
"name" : "subProduct2",
"mrp" : 89
}
]
}]
var permissionArray = ['logistics','paymentStatus','details']
var arrFiltered = arr.map(el => {
let newEl = {}
for (let elm of permissionArray) newEl[elm] = el[elm]
return newEl
}
)
console.log(arrFiltered)
In the following solution, we divide the handling of objects and plain arrays.
We build-up a "qualified key" corresponding to the equivalent string in the permissions array, as we recursively descend into an object along its properties.
If we hit a primitive value, then we end the recursion for that property.
A new object sanitized is created for each level of the recursion to contain only the permitted properties.
const data = [{ "createdBy": "Tom", "logistics": 0, "paymentStatus": "Paid", "orderAmount": 5393.75, "details": { "street": "S.S road", "postCOde": "440111" }, "subOrders": [{ "name": "sub Product1", "mrp": 12 }, { "name": "subProduct2", "mrp": 89 }] }]
const isPrimitive = (x)=>x === null || typeof x !== "object"
function sanitize(o, permissions, prefix='') {
if (isPrimitive(o)) return o
const sanitized = {}
for (const[k,v] of Object.entries(o)) {
const qk = `${prefix}${k}`
if (permissions.some((p)=>p.match(new RegExp(`^${qk}`)))) {
sanitized[k] = Array.isArray(v)
? sanitizeArray(v, permissions, `${qk}.`)
: sanitize(v, permissions, `${qk}.`)
}
}
return sanitized
}
const sanitizeArray = (arr,permissions,prefix='')=>arr.map((el)=>sanitize(el, permissions, prefix))
const permissions = ['logistics', 'paymentStatus', 'details.street', 'subOrders.name']
const sanitized = sanitizeArray(data, permissions)
console.log(sanitized)

How can I create a new object that only contains the key/value pairs specified in an array?

I want to pass a function an array of keys and an object, and return a new object that only contains the key/value pairs that I specify in the keys array.
So if I had an object like this:
{"name" : "John Smith", "position" : "CEO", "year" : "2019" }
And I passed the array
["name", "year"]
the new object returned would be:
{"name" : "John Smith", "year" : "2019" }
I've been playing around with it, but my code is not working.
function parse(keys, data) {
let obj = JSON.parse(data);
let newObj = {};
keys.array.forEach(element => {
newObj[element] = obj.element;
});
return newObj;
};
You dont need to do parse.Secondly this line keys.array.forEach is wrong. This is because there is no array key inside keys.Also replace obj.element; with data[element]
let data = {
"name": "John Smith",
"position": "CEO",
"year": "2019"
}
let keys = ["name", "year"]
function parse(keys, data) {
let newJson = {};
keys.forEach(element => {
newJson[element] = data[element];
});
return newJson;
};
console.log(parse(keys, data))
One way to achieve this would be through filtering an array of object entries:
const entries = Object.entries({
"name" : "John Smith",
"position" : "CEO",
"year" : "2019"
})
entries contains:
[
[
"name",
"John Smith"
],
[
"position",
"CEO"
],
[
"year",
"2019"
]
]
Filtering out keys:
const filteredEntries = entries.filter(([ key ]) => ["name", "year"].includes(key))
filteredEntries contains:
[
[
"name",
"John Smith"
],
[
"year",
"2019"
]
]
Last step - construct an object:
const filteredObject = Object.fromEntries(filteredEntries)
filteredObject contains:
{
"name": "John Smith",
"year": "2019"
}
Putting it together as a function:
function filterObjectByGivenKeys(object, keys) {
const filteredEntries = Object
.entries(object)
.filter(([ key ]) => keys.includes(key))
return Object.fromEntries(filteredEntries)
}
Or, if we prefer reduce and more terse syntax:
const filterObjectByGivenKeys = (object, keys) =>
Object.entries(object)
.filter(([ key ]) => keys.includes(key))
.reduce((obj, [key, value]) => ({ ...obj, [key]: value }), {})
The correct (e.g., lazy) way to accomplish this would to use lodash, because code you don't write is code you don't have to maintain:
const pick = require('lodash.pick');
const obj = {
name : 'John Smith' ,
position : 'CEO' ,
year : '2019',
};
const desired = [ 'name', 'year' ];
const filtered = pick(obj, desired );
If you want to roll your own, something like this should do the trick:
function filter_obj(obj = {}, keys = [] ) {
if ( !keys || !keys.length ) return obj;
const desired = new Set(keys);
const filtered = {};
for ( [ key, value ] of Object.entries(obj) ) {
if ( !desired.has(key) ) continue;
filtered[key] = value;
}
return filtered;
}
I think your code is close.
Maybe try:
newObj[element] = obj[element];
instead of
newObj[element] = obj.element
That way you will use the variable element instead of trying to look up the key "element" which will return undefined.
To achieve expected result, use below option of using for in to loop object keys
Loop keys by for in
Check key with the filtered keys
Add to new object
var obj = {"name" : "John Smith", "position" : "CEO", "year" : "2019" }
var fil = ["name", "year"]
var result = {}
for(let key in obj){
if(fil.indexOf(key) !==-1){
result[key] = obj[key]
}
}
console.log(result)
Another option is to use the reduce method:
var input = {"name" : "John Smith", "position" : "CEO", "year" : "2019" };
var properties = ["name", "year"];
function getNewObject(json, props) {
// Get all object properties
var availableProperties = Object.keys(json);
// Loop through the requested properties and return the object
return props.reduce((pv, cv) => {
// Check if the property exists on the object
if(availableProperties.includes(cv)){
pv[cv] = json[cv]
}
return pv;
}, {});
}
console.log(getNewObject(input, properties));
I have removed the object parsing you had above since your object isn't stringified... If it was stringified the "" would be wrapping the entire object... in production you can simple add in the parsing if needed.
function parse(keys, data) {
let newObj = {};
for (const dataKey in data){
for (let i = keys.length - 1; i >= 0; i--) {
if (data.hasOwnProperty(keys[i])) {
newObj[keys[i]] = data[keys[i]];
}
}
}
return newObj;
};
you do that using filter and Object entries or you can also use reduce.
const person = {
"name": "John Smith",
"position": "CEO",
"year": "2019",
"job": "front-end"
};
const formatObject = (arr, o) => {
let finalObject = {};
Object.entries(o).filter(([key, value]) => {
if (arr.includes(key)) {
finalObject = {
...finalObject,
[key]: value
}
}
});
return finalObject;
}
console.log(formatObject(["name", "year", "job"], person))
First add this line {"name" : "John Smith", "position" : "CEO", "year" : "2019" } inside single quotation, or you don't need to use JSON.parse:
'{"name" : "John Smith", "position" : "CEO", "year" : "2019" }'
Then you don't need the array, only keys, keys.array.forEach.
And obj[element]:
keys.forEach(element => {
newObj[element] = obj[element];
});

JavaScript - Return object key and value when both are strings

So, I have this array of objects:
var obj = [{
"Has the house been sold?": "N"
}, {
"Is the house on the market?": "Y"
}, {
"Duration of Sale": "2 weeks"
}];
and I am trying to turn it so that it key and value are like this:
var obj = [
{key: 'Has the house been sold?', value: 'N'}
];
But I cannot find a way to grab the key text because it only gives me the index.
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
var val = obj[key];
console.log(val);
}
}
Can someone help me out here? What am I missing?
You could use Array#map and Object.keys for own properties.
var obj = [{ "Has the house been sold?": "N" }, { "Is the house on the Market?": "Y" }, { "Duration of Sale": "2 weeks" }],
array = obj.map(function (a) {
var key = Object.keys(a)[0];
return { key: key, value: a[key] };
});
console.log(array);
ES6
var obj = [{ "Has the house been sold?": "N" }, { "Is the house on the Market?": "Y" }, { "Duration of Sale": "2 weeks" }],
array = obj.map(a => (key => ({ key:key, value: a[key] }))(Object.keys(a)[0]));
console.log(array);
Use Array.map().
var obj = [{
"Has the house been sold?": "N"
}, {
"Is the house on the market?": "Y"
}, {
"Duration of Sale": "2 weeks"
}];
var newObj = obj.map(function(ea, i){
var thisKey = Object.keys(ea)[0];
return {key: thisKey, value: ea[thisKey]};
});
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
You need to loop through each item in obj since it is an array, and then for each item, loop through its properties and then save them.
var obj = [{
"Has the house been sold?": "N"
}, {
"Is the house on the market?": "Y"
}, {
"Duration of Sale": "2 weeks"
}];
var newObj = [];
for (var i = 0; i < obj.length; i++) {
for (var key in obj[i])
{
newObj.push({key: key, value: obj[i][key]})
}
}
console.log(JSON.stringify(newObj))
Or just with a forEach
var arr = [];
obj.forEach(item => {arr.push({key : Object.keys(item)[0], value : item[Object.keys(item)][0]})})
console.log(arr);

Categories