Correct way to loop through an JSON object [duplicate] - json

This question already has answers here:
Unable to iterate through JSON array
(3 answers)
Closed 6 years ago.
Since there seems nobody is able to find a solution for my problem, I would like to ask my question in a different way:
What should be the correct way to loop through the games section of the following object:
[
{
"_id": "5710b0ddab8b724011705037",
"username": "test",
"name": "testuser",
"__v": 0,
"library": {
"games": [
{
"platform": [
"17",
"94"
],
"name": "Simcity",
"id": "37620"
},
{
"platform": [
"146",
"20"
],
"name": "destiny",
"id": "36067"
}
],
"platforms": [
{
"name": "Xbox360",
"id": "20"
},
{
"name": "PC",
"id": "94"
}
]
}
}
]
This object is fetched out through mongoose out of a MongoDB, all happens in the API section of my NodeJS application:
.get('/test', function(req, res){
User.findOne({"username": req.decoded.username}, function(err, user){
// trying to loop here
});
})
I have tried everything I find, but I cannot get it to work, so I wonder what ways you use to do this, without cluttering your vision with my (maybe wrong) ways and errors...

Use for...in to loop through Javascript/JSON objects
for (variable in object) {...
}
for...in documentation
Use forEach to loop through Javascript/JSON arrays
arr.forEach(callback[, thisArg])
forEach documentation

Updated Answer:
Your edit markedly changes the structure of the data compared to your original question.
Now, you have an array containing one entry, which has library, which has games, so you reference it (assuming user points to the whole thing) as user[0].library.games. E.g.:
user[0].library.games.forEach(function(entry) {
// Use `entry` here
});
var user = [{
"_id": "5710b0ddab8b724011705037",
"username": "test",
"name": "testuser",
"__v": 0,
"library": {
"games": [{
"platform": [
"17",
"94"
],
"name": "Simcity",
"id": "37620"
}, {
"platform": [
"146",
"20"
],
"name": "destiny",
"id": "36067"
}],
"platforms": [{
"name": "Xbox360",
"id": "20"
}, {
"name": "PC",
"id": "94"
}]
}
}];
user[0].library.games.forEach(function(entry) {
log(entry.name);
});
function log(msg) {
var p = document.createElement('p');
p.appendChild(document.createTextNode(msg));
document.body.appendChild(p);
}
Original Answer:
games is an array, assuming you have o referencing that object, you can reference it from o.user.library.games.
There are lots of ways to loop over arrays (see this answer for a list); one of them is forEach:
o.user.library.games.forEach(function(entry) {
// Use `entry` here, e.g. `entry.name`, `entry.id`, etc.
});
E.g.:
var o = {
"user": {
"name": "testuser",
"library": {
"platforms": [{
"id": "20",
"name": "Xbox360"
}, {
"id": "94",
"name": "PC"
}],
"games": [{
"id": "37620",
"name": "Simcity",
"platform": [
"17",
"94"
]
}, {
"id": "36067",
"name": "destiny",
"platform": [
"146",
"Xbox360"
]
}]
}
}
};
o.user.library.games.forEach(function(entry) {
log(entry.name);
});
function log(msg) {
var p = document.createElement('p');
p.appendChild(document.createTextNode(msg));
document.body.appendChild(p);
}
From your comment below, it sounds like the structure may not be quite as you quoted it in the question. You can use node-inspector to debug your NodeJS code, set a breakpoint at the beginning of where you want to loop, and inspect the variable you have referring to the object. That will show you its structure. It's very easy to install (npm install -g node-inspector) and use (node-debug your-main-file.js).

Related

lodash sort an array of objects by a property which has an array of objects

I have a an object. I am able to sort the items by using lodash's _.orderBy().
However, in one of the scenario I have to sort by subject, which is an array of objects. Items inside the subject array are already sorted based on the name.
As subject is an array of the objects, I need to consider the first item for sorting.
[
{
"id": "1",
"name": "peter",
"subject": [
{
"id": "1",
"name": "maths"
},
{
"id": "2",
"name": "social"
}
]
},
{
"id": "2",
"name": "david",
"subject": [
{
"id": "2",
"name": "physics"
},
{
"id": "3",
"name": "science"
}
]
},
{
"id": "3",
"name": "Justin",
"subject": [
]
}
]
You can use _.get() to extract the name (or id) of the 1st item in subjects. If no item exists, _.get() will return undefined, which can be replaced with a default value. In this case, we don't want to use an empty string as a default value, since the order would change. Instead I'm checking if the value is a string, if it is I use lower case on it, if not I return it as is.
const arr = [{"id":"1","name":"peter","subject":[{"id":"1","name":"maths"},{"id":"2","name":"social"}]},{"id":"2","name":"david","subject":[{"id":"2","name":"physics"},{"id":"3","name":"science"}]},{"id":"3","name":"Justin","subject":[]}]
const result = _.orderBy(arr, o => {
const name = _.get(o, 'subject[0].name')
return _.isString(name) ? name.toLowerCase() : name
})
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
Use _.sortBy with a comparison/sorting function argument. Your function itself can look into the receiving arguments subject key (I think its the subject you want to compare?)
Since you have the question also tagged with ES6 here is an JS only solution via Array.sort:
let arr = [ { "id": "1", "name": "peter", "subject": [ { "id": "1", "name": "maths" }, { "id": "2", "name": "social" } ] }, { "id": "2", "name": "david", "subject": [ { "id": "2", "name": "physics" }, { "id": "3", "name": "science" } ] }, { "id": "3", "name": "Justin", "subject": [] }, ]
const result = arr.sort((a,b) =>
a.subject.length && b.subject.length
? a.subject[0].name.localeCompare(b.subject[0].name)
: a.subject.length ? -1 : 1)
console.log(result)

How to display the position within an array with Cosmos DB SQL

I have a problem attempting to select from a document array in Cosmos-db. (SQL-api)
I am able to select the values from the array however I would like to be able to display each of the values position within the array also.
Sample JSON document:
{
"Type": "SampleJSONMessage",
"Version": "1",
"Reference": "Test",
"DateTime": "2019-03-29T15:16:11.503Z",
"Configuration": {
"MessageType": "1",
"MessageConfig": "100",
"Source": [
{
"Source": "Stream1"
},
{
"Source": "Stream2"
},
{
"Source": "Stream3"
},
{
"Source": "Stream4"
}
]
}
}
I execute this:
select c.Configuration.Source from c
which returns this:
[
{
"Source": "Stream1"
},
{
"Source": "Stream2"
},
{
"Source": "Stream3"
},
{
"Source": "Stream4"
}
]
This is what I would like to display:
[
{
"Source": "Stream1" ,
"Position": "1"
},
{
"Source": "Stream2",
"Position": "2"
},
{
"Source": "Stream3",
"Position": "3"
},
{
"Source": "Stream4",
"Position": "4"
}
]
Any help appreciated!
While a specific index is stored inside CosmosDB for each array element, the SQL API doesn't currently have a method for accessing it directly. A user defined function will work though.
Here is the UDF I added to my collection:
function ADD_INDEX(array){
array.forEach(function(item, index){item.Position = index.toString()});
return array;
}
And the modified query to use this to get the output you want:
select udf.ADD_INDEX(c.Configuration.Source) AS Source from c

What is the most efficient way to aggregate a value from a JSON tree in d3.js?

Assume you have a D3 JSON input with an unordered tree hierarchy like this:
{
"generated": "2017-02-21T14:02:18.652071",
"name": "root",
"children": [
{
"name": "level1",
"module_name": "level1",
"children": [
],
"size": "16"
},
{
"authorid": "46f14ba664314322e217383c4166d9e89892de93cbe2bb6bf2ea1645f910a24955c22fd384924a2f715efa34d07149ba284c2947c788f7c25a99308dfb2d7a6c",
"name": "child.js",
"weight": "1.0",
"module_name": "child.js",
"children": [
],
"size": "14"
},
{
"authorid": "46f14ba664314322e217383c4166d9e89892de93cbe2bb6bf2ea1645f910a24955c22fd384924a2f715efa34d07149ba284c2947c788f7c25a99308dfb2d7a6c",
"name": "child_1.js",
"weight": "1.0",
"module_name": "child_1.js",
"children": [
{
"authorid": "e5b333a985d12c2f0ccc878fc81d5e3d04732ef398631022443e25c2372e165f4f0d3d61f3f8caf8ccf4fa6e6af336834062d883d52fd3b67b2e15bd8599207a",
"name": "child_1_1.js",
"module_name": "child_1_1.js",
"children": [
],
"size": "112"
},
],
"size": "14"
},
{
"authorid": "e5b333a985d12c2f0ccc878fc81d5e3d04732ef398631022443e25c2372e165f4f0d3d61f3f8caf8ccf4fa6e6af336834062d883d52fd3b67b2e15bd8599207a",
"name": "child_3.js",
"module_name": "child_3.js",
"children": [
],
"size": "133"
}...
The structure can have any depth.
Now we need to aggregate / group all "authorid" values so we have a grouped array / map of the containing hashes of all authors from the nested JSON tree like this:
[
"46f14ba664314322e217383c4166d9e89892de93cbe2bb6bf2ea1645f910a24955c22fd384924a2f715efa34d07149ba284c2947c788f7c25a99308dfb2d7a6c",
"e5b333a985d12c2f0ccc878fc81d5e3d04732ef398631022443e25c2372e165f4f0d3d61f3f8caf8ccf4fa6e6af336834062d883d52fd3b67b2e15bd8599207a",
]
All duplicates should be aggregated as string values into a grouped value list.
The purpose of the resulting array is to filter a html table from the according node entrys that are visible in the d3 chart.
What is the most elegant way to reach this without plain javascript recursion. Is it possible to use a nested JSON as input for d3.nest or is there another performant way i.e. filter to get the above result?
If you are free to use ES6 features, one of the cleanest solutions can be implemented using a generator function for recursively walking through the data structure in combination with a Set allowing only unique entries.
function* getAuthorIds(arr) {
for (let {authorid, children} of arr) {
if (authorid) yield authorid;
if (children) yield* getAuthorIds(children);
}
}
var uniqueAuthorIds = [...new Set(getAuthorIds(data))];
The generator function gets passed an array of objects over which it will iterate using a for-of loop. It will yield the authorid if the object contains a property of this name. After that, it checks, if the object contains an array of children and, if it does, delegates to the generator for these children by using yield*. This is where recursion happens to walk through the entire hierarchy.
To get a collection of unique authorids you can construct a Set from all values of authorid, which were found throughout your data. The Set by definition guarantees the values stored in it to be unique. The trick here is to pass the generator created for your data by calling getAuthorIds(data) directly to the Set's constructor. This is possible because the constructor accepts an iterable object, i.e. an object implementing the iterable protocol, which is exactly what a Generator implicitly does.
Because in your question you asked for an array of authorids, as a last step, an array is created from the Set using the spread operator.
Have a look at the following working demo:
var data = [{
"generated": "2017-02-21T14:02:18.652071",
"name": "root",
"children": [{
"name": "level1",
"module_name": "level1",
"children": [
],
"size": "16"
}, {
"authorid": "46f14ba664314322e217383c4166d9e89892de93cbe2bb6bf2ea1645f910a24955c22fd384924a2f715efa34d07149ba284c2947c788f7c25a99308dfb2d7a6c",
"name": "child.js",
"weight": "1.0",
"module_name": "child.js",
"children": [
],
"size": "14"
}, {
"authorid": "46f14ba664314322e217383c4166d9e89892de93cbe2bb6bf2ea1645f910a24955c22fd384924a2f715efa34d07149ba284c2947c788f7c25a99308dfb2d7a6c",
"name": "child_1.js",
"weight": "1.0",
"module_name": "child_1.js",
"children": [{
"authorid": "e5b333a985d12c2f0ccc878fc81d5e3d04732ef398631022443e25c2372e165f4f0d3d61f3f8caf8ccf4fa6e6af336834062d883d52fd3b67b2e15bd8599207a",
"name": "child_1_1.js",
"module_name": "child_1_1.js",
"children": [
],
"size": "112"
}],
"size": "14"
}, {
"authorid": "e5b333a985d12c2f0ccc878fc81d5e3d04732ef398631022443e25c2372e165f4f0d3d61f3f8caf8ccf4fa6e6af336834062d883d52fd3b67b2e15bd8599207a",
"name": "child_3.js",
"module_name": "child_3.js",
"children": [
],
"size": "133"
}]
}];
function* getAuthorIds(arr) {
for (let {authorid, children} of arr) {
if (authorid) yield authorid;
if (children) yield* getAuthorIds(children);
}
}
var uniqueAuthorIds = [...new Set(getAuthorIds(data))];
console.log(uniqueAuthorIds);
I think d3 is not needed for this task as a simple recursive function should fit pretty well.
var ids = [];
function collectAuthorIdsRecursively(elem) {
for (var i = 0; i < elem.children.length; i++) {
var child = elem.children[i];
if (child.hasOwnProperty('authorid') && ids.indexOf(child.authorid) < 0) {
ids.push(child.authorid);
}
if (child.hasOwnProperty('children') && child.children instanceof Array) {
collectAuthorIdsRecursively(child);
}
}
}
collectAuthorIdsRecursively(data);
jsfiddle example
Try this :
var jsonObj = {
"generated": "2017-02-21T14:02:18.652071",
"name": "root",
"children": [{
"name": "level1",
"module_name": "level1",
"children": [
],
"size": "16"
}, {
"authorid": "46f14ba664314322e217383c4166d9e89892de93cbe2bb6bf2ea1645f910a24955c22fd384924a2f715efa34d07149ba284c2947c788f7c25a99308dfb2d7a6c",
"name": "child.js",
"weight": "1.0",
"module_name": "child.js",
"children": [
],
"size": "14"
}, {
"authorid": "46f14ba664314322e217383c4166d9e89892de93cbe2bb6bf2ea1645f910a24955c22fd384924a2f715efa34d07149ba284c2947c788f7c25a99308dfb2d7a6c",
"name": "child_1.js",
"weight": "1.0",
"module_name": "child_1.js",
"children": [{
"authorid": "e5b333a985d12c2f0ccc878fc81d5e3d04732ef398631022443e25c2372e165f4f0d3d61f3f8caf8ccf4fa6e6af336834062d883d52fd3b67b2e15bd8599207a",
"name": "child_1_1.js",
"module_name": "child_1_1.js",
"children": [
],
"size": "112"
}],
"size": "14"
}]
};
var arr = [];
function checkKey(object) {
if(object.hasOwnProperty('authorid'))
arr.push(object.authorid);
for(var i=0;i<Object.keys(object).length;i++) {
if(typeof object[Object.keys(object)[i]]=="object"){
checkKey(object[Object.keys(object)[i]]);
}
}
}
checkKey(jsonObj);
console.log(arr);

How to parse this JSON in PHP

I build this JSON from my form generated on my website.
I now want to push the individual item's to the database, so I need to be able to pull out instruction by iteration.
$instruction0
$instruction1
and the ingredients which sit inside an instruction.
When trying to parse the JSON I get an error, I am not sure how to read it in PHP. (AKA PHP NOOB) I am able to get all my item's needed via Python without any issues.
Error
[
[
{
"instruction": "Enter text here...asdada"
},
{
"ingredient": "Beetroot",
"amount": "2",
"type": "grams"
},
{
"ingredient": "Beetroot",
"amount": "1",
"type": "grams"
}
],
[
{
"instruction": "Enter text here..sdfsdf."
},
{
"ingredient": "Carrot",
"amount": "2",
"type": "grams"
},
{
"ingredient": "Beetroot",
"amount": "525",
"type": "grams"
}
]
]
Have you tried json_decode with a second parameter 'true' to specify you want your output as an associative array.
json_decode($json, true);
Secondly, if you are posting this json string manually into your code, you need to wrap it inside quotes, so based on that
$json = '[ [ { "instruction": "Enter text here...asdada" }, { "ingredient": "Beetroot", "amount": "2", "type": "grams" }, { "ingredient": "Beetroot", "amount": "1", "type": "grams" } ], [ { "instruction": "Enter text here..sdfsdf." }, { "ingredient": "Carrot", "amount": "2", "type": "grams" }, { "ingredient": "Beetroot", "amount": "525", "type": "grams" } ] ] ';
$array = json_decode($json, true);
Then you can iterate through $array as normal

Linq to Json using Like Clause

I've got an MVC 3 web app and am returning a JSON object which I would like to use Linq against to limit the result returned to the client jquery.
The Json response takes the following structure:
{
"Data": {
"Items": [
{
"Result": {
"Id": "e2ba4912-c387-4f54-b55e-06742a6858db",
"Name": "SomeOtherSetting",
"Value": "500",
"Archived": false
},
"Result": {
"Id": "17c27584-cea8-42c2-b6c4-0b30625ac3ce",
"Name": "Setting2",
"Value": "600",
"Archived": false
},
"Result": {
"Id": "17c27584-cea8-42c2-b6c4-0b30625ac3ce",
"Name": "Setting3",
"Value": "700",
"Archived": false
}
}]
}
}
....
I need to return or grab just the json items that have a Name like 'Setting' for example. In the example, this would return just the 2 Json nodes.
My Linq is very limited and what I have is: Settings is where the Json response is stored.
NewtonSoft.Json.Linq.JObject data = NewtonSoft.Json.Linq.JObject.Parse(Settings);
var result = from p in data["Data"]["Items"].Children()
where (p["Result"]["Name"].Contains("Expenses.Help.Tip"))
select new { Name = (string)p["Result"]["Name"], Value = (string)p["Result"]["Value"] };
When I run this I get nothing in my result. Can anyone help and tell me what I'm doing wrong?
Thanks.
Well, I'm not a Json specialist, but I think your Json structure has some problems.
I tried an online parser, and parsing took only the third result... (try to copy past your code in the left window, and look at JS eval.
Instead of
"Items": [
{
"Result": {
},
"Result": {
},
"Result": {
}
}]
you should have each element of Items array (each 'Result') into {}.
"Items": [
{
{"Result": {
}
},
{"Result": {
}
},
{"Result": {
}
}]
I got it to work by changing your Json file to
{
"Data": {
"Items": [
{
"Result": {
"Id": "e2ba4912-c387-4f54-b55e-06742a6858db",
"Name": "SomeOtherSetting",
"Value": "500",
"Archived": false
}
},
{
"Result": {
"Id": "17c27584-cea8-42c2-b6c4-0b30625ac3ce",
"Name": "Setting2",
"Value": "600",
"Archived": false
}
},
{
"Result": {
"Id": "17c27584-cea8-42c2-b6c4-0b30625ac3ce",
"Name": "Setting3",
"Value": "700",
"Archived": false
}
}]
}
}
using
var data = JObject.Parse(test)["Data"]["Items"].Children()
.Where(m => m["Result"]["Name"].Value<string>().Contains("Setting"))
.Select(m => new
{
Name = m["Result"]["Name"].Value<string>(),
Value = m["Result"]["Value"].Value<int>()
})
.ToList();