JSON data concatenate two data [duplicate] - javascript

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.

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...

How to push values to an object from inside a map function when a condition is met?

How can we push values to an object from inside a map function and return that single object. I have string comparison condition inside the map function. I tried using Object.assign but it returns an array with multiple object inside that array. Instead of this multiple object I'm expecting a single object inside an array.
Map function
let arrayObj = arrayToTraverse.map(function(item) {
var myObj = {};
if(item.inputvalue === 'Name'){
Object.assign(myObj, {name: item.value});
} else if (item.inputvalue === 'Email'){
Object.assign(organizerInfo, {email: item.value});
} else if (item.inputvalue === 'Company'){
Object.assign(organizerInfo, {company: item.value});
}
return myObj;
});
console.log("The array object is", arrayObj)
This return the array of objects as follows
[
{
"name": "Tom"
},
{
"email": "tom#abc.com"
},
{
"company": "ABC"
}
]
But The array I'm expecting is
[
{
"name": "Tom",
"email": "tom#abc.com",
"company": "ABC"
}
]
// or
[
"returned": {
"name": "Tom",
"email": "tom#abc.com",
"company": "ABC"
}
]
An example of arrayToTraverse can be considered as following
[
{
"id": "1",
"inputvalue": "Name",
"value": "Tom",
"type": "Short Text"
},
{
"id": "2",
"inputvalue": "Email",
"value": "tom#abc.com",
"type": "Email ID"
},
{
"id": "3",
"inputvalue": "Company",
"value": "Google",
"type": "Long Text"
}
]
Simply put, you're trying to reduce an array to a single object, not map one array to another.
var arrayToTraverse = [
{inputvalue:"Name",value:"Tom"},
{inputvalue:"Email",value:"tom#abc.com"},
{inputvalue:"Company",value:"ABC"},
{inputvalue:"Foo",value:"Bar"} // wont show up
];
var valuesRequired = ["Name","Email","Company"];
var result = arrayToTraverse.reduce( (acc, item) => {
if(valuesRequired.includes(item.inputvalue))
acc[item.inputvalue.toLowerCase()] = item.value;
return acc;
}, {});
console.log(result);
Edit: Added lookup array for required fields.

Testing values of array objects

If i have an array like:
[
{ "user": "tom",
"email": "ee#co.com"
},
{ "user": "james",
"email": "bb#co.com"
},
{ "user": "ryan",
"email": "rr#co.com"
}
]
But it's not always being returned in that order - how can i check if ryan, for example, exists somewhere in one of these objects?
If you are already using lodash (or want to) then I would use its find:
_.find(array, { user: "ryan" })
Or with a few more characters you can do it without lodash:
array.find(elem => elem.user === "ryan")
Both return undefined if a matching element is not found.
Function return true if array contains ryan.
var input = [
{ "user": "tom",
"email": "ee#co.com"
},
{ "user": "james",
"email": "bb#co.com"
},
{ "user": "ryan",
"email": "rr#co.com"
}
]
var output = input.some(function(eachRow){
return eachRow.user === 'ryan';
});
console.log(output);
My method to solve that is to extract the targeted fields into arrays then check the value.
const chai = require('chai');
const expect = chai.expect;
describe('unit test', function() {
it('runs test', function() {
const users = [
{ "user": "tom",
"email": "ee#co.com"
},
{ "user": "james",
"email": "bb#co.com"
},
{ "user": "ryan",
"email": "ryan#co.com"
}
];
const names = extractField(users, 'user'); // ['tom', 'james', 'ryan']
expect(names).to.include('ryan');
});
function extractField(users, fieldName) {
return users.map(user => user[fieldName]);
}
});
I'm using chai for assertion. In case you want to check in other fields, we just use the extract methods.
const emails = extractField(users, 'email');
expect(emails).to.include('ryan');
Hope it helps

How can I get unordered array of keys from object

I have data from backend in my js like this:
var list = {
"6": {
"id": 6,
"name": "John",
"age": 31
},
"42": {
"id": 42,
"name": "Alex",
"age": 25
},
"3": {
"id": 3,
"name": "Tim",
"age": 58
},
};
Then I need to display this data in my angular html template through ngFor directive. But first I have to get an array of object keys:
var listKeys= Object.keys(list);
Next I can output data in template:
<div *ngFor="let item of listKeys">
<p>{{list[item].id}}</p>
<p>{{list[item].name}}</p>
<p>{{list[item].age}}</p>
<hr>
</div>
But the problem is that order of my data changed. I have in listKeys next array ["3", "6", "42"]. But I want to have original order in that one ["6", "42", "3"]. One of solutions that I have found is make keys as not numeric string. For example:
var list = {
"+6": {...},
"+42": {...},
"+3": {...},
};
But I don't have access to backend. I need another solution.
P.S. The way in which I get data from the backend
getData() {
this._dataService.getList(this.name, this.age).subscribe(res => {
this.list = JSON.parse(JSON.stringify(res));
this.listKeys = Object.keys(this.list);
});
}
By definition, an object is an unordered collection of properties. As a solution, you could use an array instead of an object:
The first step would be to convert the response from the server to an array in the same order.
// Original JSON string received from API
var jsonString = `{
"6": {
"id": 6,
"name": "John",
"age": 31
},
"42": {
"id": 42,
"name": "Alex",
"age": 25
},
"3": {
"id": 3,
"name": "Tim",
"age": 58
}
}`;
// Array of ordered id's
const orderedIds = [];
// Find all id's in the JSON string and push them to the array
const pattern = /"?id"?\: (\d*)/g;
let match;
while (match = pattern.exec(jsonString)) {
orderedIds.push(parseInt(match[1]));
}
// parse the original JSON object
const originalList = JSON.parse(jsonString);
// resulting ordered Array
const result = [];
// Push the object in the array by order
for(x of orderedIds) {
result.push(originalList[x]);
}
// Log the resulting array
document.getElementById("result").innerText = JSON.stringify(result);
<pre id="result"></pre>
The result will be an array of the objects in the same order as they appeared in the JSON string:
result = [
{
"id": 6,
"name": "John",
"age": 31
},
{
"id": 42,
"name": "Alex",
"age": 25
},
{
"id": 3,
"name": "Tim",
"age": 58
},
];
After this you can use it in your template:
<div *ngFor="let item of result">
<p>{{item.id}}</p>
<p>{{item.name}}</p>
<p>{{item.age}}</p>
<hr>
</div>
this array does garantee the order of its values.
This is bound to have edge cases, but adding it because it works
If you are getting the data from the backend in the form of JSON then you can do the following
note: var json is a placeholder, as you haven't shown HOW you get your data
var json = `{
"6": {
"id": 6,
"name": "John",
"age": 31
},
"42": {
"id": 42,
"name": "Alex",
"age": 25
},
"3": {
"id": 3,
"name": "Tim",
"age": 58
}
}`;
var result = JSON.parse(json.replace(/\s?"(\d+)":/g, '"$1 ":'));
console.log(Object.keys(result));
Again, this is bound to fail, but I can't see any other way you can "fix" this on the client side - I thought JSON.parse "reviver" function would help, but it gets the properties in 3, 6, 42 order as well - so, no use at all

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