JSON/JavaScript - Getting value by passing index and property name - javascript

For the following JSON:
var myJSON =
{ "employee": [
{
"firstName": "John",
"lastName": "Doe",
"Age": 20
},
{
"firstName": "Jane",
"lastName": "Moe",
"Age": 35
},
{
"firstName": "Mike",
"lastName": "Poe",
"Age": 28
}
]
};
Let's say I need to grab a particular value by passing an index and a property name. For example, employee[1].lastName would give me the value "Moe". But, I'm having some rough time figuring out what's supposed to be a simple JavaScript function that takes these two values as input and returns the value as output. The following code doesn't seem to work:
function getValue(index, attrName) {
var val = eval("myJSON.employee[" + index + "]." + attrName); // is using eval() even a sound approach?
return val;
}

This should do it.
var myJSON =
{ "employee": [
{
"firstName": "John",
"lastName": "Doe",
"Age": 20
},
{
"firstName": "Jane",
"lastName": "Moe",
"Age": 35
},
{
"firstName": "Mike",
"lastName": "Poe",
"Age": 28
}
]
};
function getValue(index, attrName) {
return myJSON['employee'][index][attrName];
}
getValue(1,'lastName')
Outputs: "Moe".
Attribute accessors var['attr'] and var.attr are identical, except that some attribute names cannot be expressed like var.attr. Suppose your attribute name is "foo-bar". The code var.foo-bar is not correct so you'd have to use var['foo-bar']. Also, you can address global variables with window['var-name'].

Related

How to resolve error: "undefined" when reading single values from JSON using JavaScript?

I have a JavaScript function that outputs all values from a JSON file to a Terminal, but when attempting to print a single value, I get the following error: Line 74 - Cannot read properties of undefined (reading 'width')
Here is the code:
var json = `{
"columns": [{
"fname": "John",
"lname": "Doe",
"age": "23"
},
{
"fname": "Jane",
"lname": "Doe",
"age": ""
},
{
"fname": "Tom",
"lname": "Johns",
"age": ""
},
{
"fname": "Brian",
"lname": "Wicks",
"age": "27"
},
{
"fname": "Tim",
"lname": "Stone",
"age": ""
},
{
"fname": "Fred",
"lname": "Wilson",
"age": ""
},
{
"fname": "Jason",
"lname": "Voorhees",
"age": "90"
}
],
"rows": [{
"data": {
"width": "2",
"height": "7",
"length": "",
"finalresult": "44",
"firstresult": "",
"secondresult": "300.00",
"thirdresult": "700.40"
}
}]
}`;
var obj = JSON.parse(json);
function printValues(obj) {
for(var k in obj) {
if(obj[k] instanceof Object) {
printValues(obj[k]);
} else {
console.log(obj[k] + "\n");
};
}
};
// Printing all the values from the resulting object
printValues(obj);
//print single value
//console.log(obj["columns"]["rows"]["data"]["width"] + "\n");
console.log("Print Indiviual values:");
console.log(obj["rows"]["data"]["width"] + "\n"); //The Error
...Could I get some assistance as to what I'm doing wrong? ...Thanks
As #Yarin and #codemonkey pointed out—you're trying to access the data object as a direct object property of rows, e.g. obj.rows.data which is wrong and will return undefined because data is not a property of the rows object. Instead it's the first (and only) entry in the array of objects that is rows.
You need to either change the syntax to:
obj.rows[0].data.width
Or take the data object out of the array and remove the array so that the rows object is structured like this:
const obj = {
rows: {
data: {
width: 1
}
}
}
// Then you can use this syntax...
console.log( obj.rows.data.width )
// or even this syntax if you want to...
console.log( obj['rows']['data']['width'] )
I see that the width is the property of object data that is inside array rows...

Filtering array with objects inside an object

I have a problem with filtering an array with nested objects.
[{
"firstName": "Kevin",
"lastName": "Smith",
"expenses": {
"drink1": 25,
"drink2": 20
}
},
{
"firstName": "John",
"lastName": "Rambo",
"expenses": {
"coffe": 10,
"cake": 20
}
}
]
I want to get the objects where the sum of all expenses is > 35. How to get inside expenses? Or maybe filter is not a proper way here.
Just filter it, with a condition using reduce to sum the expenses! Pretty straight forward :)
const input = [{
"firstName": "Kevin",
"lastName": "Smith",
"expenses": {
"drink1": 26,
"drink2": 20
}
},
{
"firstName": "John",
"lastName": "Rambo",
"expenses": {
"coffe": 10,
"cake": 20
}
}
];
const output = input.filter(user => Object.values(user.expenses).reduce((acc, expense) => acc + expense) > 45);
console.log(output);
I'm assuming that you need to keep you array of users the way it is, but with the expenses filtered.
(I assumed wrong as pointed in the comment, keeping this answer just in case someone sees any value on it)
Probably this can be optmized or simplified, but here it goes:
arr.reduce((acc, user) => [...acc,
Object.keys(user).reduce((userResult, key) => {
if (key === 'expenses') {
return {
...userResult,
expenses: Object.entries(elem.expenses)
.filter(([product, value]) => value > 35)
// now "reversing" the object.entries
.reduce((acc, [product, value]) => ({ [product]: value }), {})
}
}
return {
...userResult,
[key]: elem[key]
}
}, user) // starts with the user
], []) //starts with empty array
You can try something like this
var data = [{
"firstName": "Kevin",
"lastName": "Smith",
"expenses": {
"drink1": 25,
"drink2": 20
}
},
{
"firstName": "John",
"lastName": "Rambo",
"expenses": {
"coffe": 10,
"cake": 20
}
}
]
var filtered = data.filter(c => Object.keys(c.expenses)
.reduce(function(p, e) {
return p + c.expenses[e]
}, 0) >= 35
);
console.log(filtered);
You can access object at index i inside array arr with expression arr[i]
What you need to do is to loop over your array. Inside your loop you access each object with expression i have mentioned: arr[i] and then on this object you can access expenses following way arr[i].expenses after this - if i am understanding correctly you sum contents of your arr[i].expenses object and select those objects which satisfy your condition.
Please, See code below:
var expensesAbove35Arr = [];
var yourArray = [
{
"firstName": "Kevin",
"lastName": "Smith",
"expenses": {
"drink1": 26,
"drink2": 20
}
},
{
"firstName": "John",
"lastName": "Rambo",
"expenses": {
"coffe": 10,
"cake": 20
}
}
];
for(var i=0; i<yourArray.length; i++){
if(yourArray[i].expenses.coffe + yourArray[i].expenses.cake > 35 ){
expensesAbove35Arr.push(yourArray[i]);
}
}
You have got your result inside array expensesAbove35Arr
A possible solution might be:
arr.filter(function(v){
for(expense in v.expenses){
if(v.expenses[expense] > 10){
return true;
}else{
return false;
}
}
})

Filter JSON object array on multiple values or arguments javascript

users = [
{
"username": "Alice",
"firstName": "Alice-U",
"lastName": "Wonderland"
},
{
"username": "bob",
"firstName": "Bob-u",
"lastName": "Builder",
},
{
"username": "charly",
"firstName": "Charly-u",
"lastName": "Brown",
}
]
I want to be able to filter this array on multiple values like:
Search Criteria: { "username" : "Alice" } should return:
{
"username": "Alice",
"firstName": "Alice-U",
"lastName": "Wonderland"
}
Similary for: { "username" : "charly", "firstName": "Charly-u" } should return :
{
"username": "charly",
"firstName": "Charly-u",
"lastName": "Brown",
}
with exact string matching using javaScript or jQuery.
You can employ .every to check that each of the criteria keys matches:
function filterBy(list, criteria) {
return list.filter(candidate =>
Object.keys(criteria).every(key =>
candidate[key] == criteria[key]
)
);
}
let users = [
{ "username": "Alice", "firstName": "Alice-U", "lastName": "Wonderland" },
{ "username": "bob", "firstName": "Bob-u", "lastName": "Builder" },
{ "username": "charly", "firstName": "Charly-u", "lastName": "Brown" }
];
console.log(filterBy(users, { "username" : "Alice" }));
console.log(filterBy(users, { "username" : "charly", "firstName": "Charly-u" }));
Why not Array.prototype.filter()? to filter only the element that has username="Alice". By the way you can add multiple object keys inside your filter's arrow function while filtering array of object. For example:
user.username ==='Charly' && firstName==='Charly-u'
users = [{
"username": "Alice",
"firstName": "Alice-U",
"lastName": "Wonderland"
},
{
"username": "bob",
"firstName": "Bob-u",
"lastName": "Builder",
},
{
"username": "charly",
"firstName": "Charly-u",
"lastName": "Brown",
}
];
result = users.filter(user => user.username ==='Alice');
console.log(result);
can’t it be just a function with for loop?
//call
this.filterIt( ‘username’ , ‘Alice’, users);
//function
Function filterIt (key, value, arr){
result = [];
for ( a in arr){
if (a[key] == value) result.push(a);
}
return result;
}
You can write it in the following way. If you want to do exact search write a search function like this:
function search(term) {
return users.filter(({username, firstName, lastName}) => {
return username.toLowerCase() === term.toLowerCase() ||
firstName.toLowerCase() === term.toLowerCase() ||
lastName.toLowerCase() === term.toLowerCase()
})
}
Instead of comparing each key one can iterate all object properties using object.keys.
If you want to match each anything use following function
function search(term) {
return users.filter(({username, firstName, lastName}) => {
return username.toLowerCase().indexOf(term.toLowerCase()) > -1 ||
firstName.toLowerCase().indexOf(term.toLowerCase()) > -1 ||
lastName.toLowerCase().indexOf(term.toLowerCase()) > -1
})
}
This will even match searchTerm anywhere. Like if you use this as search('al'). It will return the first object, whereas the first function will need exact string like search('alice') to work.
const users = [{
"username": "Alice",
"firstName": "Alice-U",
"lastName": "Wonderland"
},
{
"username": "bob",
"firstName": "Bob-u",
"lastName": "Builder",
},
{
"username": "charly",
"firstName": "Charly-u",
"lastName": "Brown",
}
]
function searchFull(term) {
return users.filter(({
username,
firstName,
lastName
}) => {
return username.toLowerCase() === term.toLowerCase() ||
firstName.toLowerCase() === term.toLowerCase() ||
lastName.toLowerCase() === term.toLowerCase()
})
}
function search(term) {
return users.filter(({
username,
firstName,
lastName
}) => {
return username.toLowerCase().indexOf(term.toLowerCase()) > -1 ||
firstName.toLowerCase().indexOf(term.toLowerCase()) > -1 ||
lastName.toLowerCase().indexOf(term.toLowerCase()) > -1
})
}
console.log(searchFull('alice'))
console.log(search('al'))

JSON data concatenate two data [duplicate]

This question already has an answer here:
How to concatenate two string fields into one in a JavaScript array? [closed]
(1 answer)
Closed 4 months ago.
In Javascript, How can I convert this JSON Data?
I need to concatenate the firstname and lastname into its fullname
Data
[
{
"lastname": "Stark",
"firstname": "Tony",
"id": 1
},
{
"lastname": "Parker",
"firstname": "Peter",
"id": 2
},
{
"lastname": "Rogers",
"firstname": "Steve",
"id": 3
},
]
This should be the result:
Result
[
{
"fullname": "Tony Stark",
"id": 1
},
{
"fullname": "Peter Parker",
"id": 1
},
{
"fullname": "Steve Rogers",
"id": 1
},
]
Use JSON.parse to parse your data into JavaScript object and then with Array#map function iterate over the items and populate your custom objects.
const dataAsJson = `[
{
"lastname": "Stark",
"firstname": "Tony",
"id": 1
},
{
"lastname": "Parker",
"firstname": "Peter",
"id": 2
},
{
"lastname": "Rogers",
"firstname": "Steve",
"id": 3
}
]`;
const data = JSON.parse(dataAsJson);
const changedData = data.map(item => ({ fullname: `${item.firstname} ${item.lastname}`, id: item.id }));
console.log(changedData);
If this data is available to your script as a JSON string, then you can use JSON.parse() to obtain the array of objects.
Then do whatever you want with that array of objects.
Then, eventually, convert the resulting data back to a string using JSON.stringify().
You can also use array#reduce.
const data = `[{"lastname": "Stark","firstname": "Tony","id": 1},{"lastname": "Parker","firstname": "Peter","id": 2},{"lastname": "Rogers","firstname": "Steve","id": 3}]`;
var result = JSON.parse(data).reduce((arr, obj) => {
return arr.push({fullName : obj.firstname + " " + obj.lastname, id: obj.id }), arr;
},[]);
console.log(result);
First, parse the string to get the data in JSON by using
JSON.parse()
. If you're using es6, use this:
const newArray = JSON.parse(yourArray).map((user) => ({
fullName: `${user.firstname} ${user.lastname}`,
id: user.id
}));
otherwise use this:
const newArray = yourArray.map(function (user) {
return {
fullName: user.firstname + user.lastname,
id: user.id
};
});
Thanks.
Logically all you need to do is loop through the array and make a new object with the firstname and lastname contacted. So here is a non-fancy ES5 way to do this:
// JSON Data parsed into JS Object
var arr = JSON.parse('[{"lastname":"Stark","firstname":"Tony","id":1},{"lastname":"Parker","firstname":"Peter","id":2},{"lastname":"Rogers","firstname":"Steve","id":3}]');
var newArr = [];
for(var i=0; i<arr.length; i++)
newArr.push({"fullname": arr[i]["firstname"] + " " + arr[i]["lastname"], "id": arr[i]["id"]});
console.log(JSON.stringify(newArr)); // Convert to text for JSON.

Nested linq loops

Iam trying to iterate the below JSON with linq.js , Here my scenario is I am having an array which contains 3,5,6.Based on this array values i need firstName from below JSON. How can i achieve it . The JSON is just given for an example in real time am handling with 50000 records, what is the best way to achieve this?
[
{
"id": "1",
"firstName": "John",
"lastName": "Doe"
},
{
"id": "2",
"firstName": "Anna",
"lastName": "Smith"
},
{
"id": "3",
"firstName": "Peter",
"lastName": "Jones"
},
{
"id": "4",
"firstName": "John",
"lastName": "Doe"
},
{
"id": "5",
"firstName": "Anna",
"lastName": "Smith"
},
{
"id": "6",
"firstName": "Peter",
"lastName": "Jones"
},
{
"id": "7",
"firstName": "John",
"lastName": "Doe"
},
{
"id": "8",
"firstName": "Anna",
"lastName": "Smith"
},
{
"id": "9",
"firstName": "Peter",
"lastName": "Jones"
}
]
Basically what you're trying to do is a join. A naive approach would simply just do a join.
var ids = [ 3, 5, 6 ];
var query = Enumerable.From(data)
.Join(ids, "Number($.id)", "$", "$")
.ToArray();
However this wouldn't work out well when there are many objects to work with since you're performing a linear search for the associated items. You can improve things by creating a lookup of the objects by id. You'll just have to pay the up front cost of creating the lookup.
var lookup = Enumerable.From(data)
.ToObject("Number($.id)");
var ids = [ 3, 5, 6 ];
var query = Enumerable.From(ids)
.Select(function (id) {
return lookup[id];
})
.ToArray();
If you are aware of that big amount of data would hang other process, make the user feel laggy, you can try this:
var process = function(obj, targets, callback, context) {
// Init context
var results = [];
var length = obj.length;
var procLimit = 500; // Whatever the amount you want to process at a time, higher will have higher change to cause lag on browser.
context = context ? context : null;
var current = 0;
// Loop function
var looper = function() {
if (current >= length) {
callback.call(context, result);
return;
}
var end = Math.min(length, current + procLimit);
var id, findIndex;
// Only process a fixed amount of item in a time.
for (; current < end ; ++current) {
id = parseInt(obj[current].id, 10);
findIndex = targets.indexOf(id);
// Find the matched key, and put to result.
if (findIndex >= 0) {
results.push(obj[current]);
// or you just need fname, use
// results.push(obj[current].firstName);
// remove founded from targets
targets.splice(findIndex, 1);
}
}
current += procLimit;
// Non-blocking
setTimeout(looper, 10);
};
// Non-blocking
setTimeout(looper, 10);
};
// Usage
process(YOUR_OBJ, [1, 3, 5, 6], function(processedObj){
// do somthing with the processed Object
}, THE_CONTEXT);
This function will tries to run as in background, and when it complete scan through the json array, it'll call your handler with the founded items in an array as param.
If block-effect is not in concern, then simply use the filter:
var targets = [1, 3, 5, 6];
var filterResult = YOUR_JSON.filter(function(item) {
var id = parseInt(item.id, 10);
return (targets.indexOf(id) >= 0);
}).map(function(item) { return item.firstName; });

Categories

Resources