I am bit new to JSON world. And I have to use JavaScript to create following type of JSON structure. Not sure how to achieve this. Tried with following code, but unable to add second element("12101") as well as people to JSON Structure is where I am struggling.
var chat = {};
chat = {"101":{}};
chat["101"].people= {};
chat["101"].people = {"L0b12leL-Ar9GYKoAAAC":{}};
chat["101"].people.L0b12leL-Ar9GYKoAAAC = {"name":"vikram#qech.com"};
chat["101"].room= {};
JSON structure to achieve
{
"101": {
"people": {
"L0b12leL-Ar9GYKoAAAC": {
"name": "vikram#qtech.com",
"inroom": "f787f316-6424-491b-b779-cfc396f0f8a1",
"owns": "f787f316-6424-491b-b779-cfc396f0f8a1",
"countrycode": "in",
"device": "desktop",
"roomname": "R1"
},
"qKCglYWI1hRhZUZCAAAD": {
"name": "Ishim",
"inroom": "2e52905d-951c-4990-b9b7-2f3fc0602922",
"owns": "2e52905d-951c-4990-b9b7-2f3fc0602922",
"roomname": "Ra"
}
},
"room": {
"f787f316-6424-491b-b779-cfc396f0f8a1": {
"name": "R1",
"id": "f787f316-6424-491b-b779-cfc396f0f8a1",
"owner": "L0b12leL-Ar9GYKoAAAC",
"people": [
"L0b12leL-Ar9GYKoAAAC"
],
"status": "available"
},
"2e52905d-951c-4990-b9b7-2f3fc0602922": {
"name": "Ra",
"id": "2e52905d-951c-4990-b9b7-2f3fc0602922",
"owner": "qKCglYWI1hRhZUZCAAAD",
"people": [
"qKCglYWI1hRhZUZCAAAD"
],
"status": "available"
}
}
},
"12101": {
"people": {
"K-Ar9GYKoAAAC": {
"name": "Rahul.com",
"inroom": "f787f316-6424-491b-b779-cfc396f0f8a1",
"owns": "f787f316-6424-491b-b779-cfc396f0f8a1",
"countrycode": "in",
"device": "desktop",
"roomname": "R1"
},
"I1hRhZUZCAAAD": {
"name": "Vipul",
"inroom": "2e52905d-951c-4990-b9b7-2f3fc0602922",
"owns": "2e52905d-951c-4990-b9b7-2f3fc0602922",
"roomname": "Ra"
}
},
"room": {
"b779-cfc396f0f8a1": {
"name": "Rahul-R1",
"id": "f787f316-6424-491b-b779-cfc396f0f8a1",
"owner": "L0b12leL-Ar9GYKoAAAC",
"people": [
"L0b12leL-Ar9GYKoAAAC"
],
"status": "available"
},
"b9b7-2f3fc0602922": {
"name": "Vipul-Room1",
"id": "2e52905d-951c-4990-b9b7-2f3fc0602922",
"owner": "qKCglYWI1hRhZUZCAAAD",
"people": [
"qKCglYWI1hRhZUZCAAAD"
],
"status": "available"
}
}
}
}
This is invalid because the property name contains dashes.
chat["101"].people.L0b12leL-Ar9GYKoAAAC = {"name":"vikram#qech.com"};
To access it correctly, put it in quotes
chat["101"].people["L0b12leL-Ar9GYKoAAAC"] = {"name":"vikram#qech.com"};
Use bracket notation as a property accessor like this:
chat["12101"].people = {};
chat["101"].people["L0b12leL-Ar9GYKoAAAC"] = {"name":"vikram#qech.com"};
With it, it’s just a routine piece of work. It probably didn’t work right away since dot notation property access requires a valid identifier name. With bracket notation, you can use any string like "L0b12leL-Ar9GYKoAAAC".
Also note that in JSON, anything works as a property name too, as long as it is put in quotes. {"L0b12leL-Ar9GYKoAC":true} is as valid as {"💖":true}.
Related
I've been playing around trying to learn in an API project using Postman and conducting tests using JavaScript. So far, I have succeeded with the help of reading on websites and watching YouTube videos. Of course, previous tests and playing around have been fairly easy but now I came to a stop. I really tried to figure this out for several weeks but I need further guidance, a push in the right direction or direct help.
What I'm trying to do is to filter out some of the response to only view objects that contain specific data.
To do that, I'm using a filter where I want all products containing a specific value inside an array "product_option_values".
My first approach was to see if I could sort products having any values from the first array, and it worked. It filters just fine.
var filterSmall = jsonData.products.filter(fs => fs.associations.product_option_values);
My next approach was to get to my goal of filtering out products according to specific values inside this array. I tried many simple .(dot) combinations and pointing to [index] to access it without any luck. (I must add that I know how to access this from a specific product, but that way doesn't work when filtering).
I've also tried other approaches such as:
var filterSmall = jsonData.products.filter(fs => fs.associations["product_option_values", 0, "name"] === "S");
and other similar combinations.
This is a very shortened sample of the structure of "products" which in its full form consists of 20 products and far more values inside of it:
{
"products": [
{
"id": 16,
"manufacturer_name": "Graphic Corner",
"quantity": "0",
"price": "12.900000",
"indexed": "1",
"name": "Mountain fox notebook",
"associations": {
"categories": [
{
"id": "2"
},
{
"id": "6"
}
],
"product_option_values": [
{
"id": "22"
},
{
"id": "23"
}
]
}
},
{
"id": 17,
"manufacturer_name": "Graphic Corner",
"quantity": "0",
"price": "12.900000",
"indexed": "1",
"name": "Brown bear notebook",
"associations": {
"categories": [
{
"id": "2"
},
{
"id": "6"
}
],
"product_option_values": [
{
"id": "23"
},
{
"id": "24"
}
]
}
}
]
}
and here is a small and expanded sample from product_option_values:
{
"product_option_values": [
{
"id": 1,
"id_attribute_group": "1",
"color": "",
"position": "0",
"name": "S"
},
{
"id": 2,
"id_attribute_group": "1",
"color": "",
"position": "1",
"name": "M"
},
{
"id": 3,
"id_attribute_group": "1",
"color": "",
"position": "2",
"name": "L"
}
]
}
How do I proceed? Did I do anything correct or even close to it?
Perhaps I've been staring at this for too long.
Thanks in advance.
If you want to compare nested attributes you have to transform the objects (e.g. by using a map operation), so that the relevant attributes are easily accessible for a comparison. If you want to filter by product_option_value id, you could do something like this:
const jsonData = {
"products": [
{
"id": 16,
"manufacturer_name": "Graphic Corner",
"quantity": "0",
"price": "12.900000",
"indexed": "1",
"name": "Mountain fox notebook",
"associations": {
"categories": [
{
"id": "2"
},
{
"id": "6"
}
],
"product_option_values": [
{
"id": "22"
},
{
"id": "23"
}
]
}
},
{
"id": 17,
"manufacturer_name": "Graphic Corner",
"quantity": "0",
"price": "12.900000",
"indexed": "1",
"name": "Brown bear notebook",
"associations": {
"categories": [
{
"id": "2"
},
{
"id": "6"
}
],
"product_option_values": [
{
"id": "23"
},
{
"id": "24"
}
]
}
}
]
};
const sample = {
"product_option_values": [
{
"id": 22,
"id_attribute_group": "1",
"color": "",
"position": "0",
"name": "S"
},
{
"id": 2,
"id_attribute_group": "1",
"color": "",
"position": "1",
"name": "M"
},
{
"id": 3,
"id_attribute_group": "1",
"color": "",
"position": "2",
"name": "L"
}
]
};
const ids = sample.product_option_values.map((el) => String(el.id));
console.log(ids);
const filtered = jsonData.products.filter((fs) => fs.associations.product_option_values.map((e) => e.id).some((f) => ids.includes(f)));
console.log(filtered);
I'm pretty new to Javascript, and I just learned about underscore.js. I have a deeply nested JSON object, and I need to use underscore to find key/value pairs, which I will then use to populate various HTML tables. If the structure was more shallow, using something like _.pluck would be easy, but I just don't know how to traverse past the first couple of nesting levels (i.e. surveyGDB, table, tablenames). The JSON object comes from an XML that is comprised of multiple nesting structures (mashed up from different database tables).
var JSONData =
"surveyGDB": {
"filename": "..\\Topo\\SurveyGeoDatabase.gdb",
"table": {
"tablename": [
{
"#text": "SurveyInfo\n ",
"record": {
"OBJECTID": "1",
"SiteID": "CBW05583-345970",
"Watershed": "John Day",
"VisitType": "Initial visit",
"SurveyInstrument": "Total Station",
"ImportDate": "2015-07-22T09:08:42",
"StreamName": "Duncan Creek",
"InstrumentModel": "TopCon Magnet v2.5.1",
"FieldSeason": "2015"
}
},
{
"#text": "QaQcPoints\n ",
"record": [
{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tp",
"Count": "357"
},
{
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tb",
"Count": "92"
},
{
"OBJECTID": "3",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "to",
"Count": "8"
},
{
"OBJECTID": "4",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bl",
"Count": "279"
},
{
"OBJECTID": "5",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bf",
"Count": "18"
}
]
},
{
"#text": "QaQcPolygons\n ",
"record": [
{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:43:08",
"SurveyExtentCount": "",
"WaterExtentCount": "",
"ChannelUnitsCount": "",
"ChannelUnitsUnique": ""
},
{
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T13:35:15",
"SurveyExtentCount": "1",
"WaterExtentCount": "1",
"ChannelUnitsCount": "21",
"ChannelUnitsUnique": "21"
}
]
}
]
}
}
}
For instance, I wanted all of the values for 'Code' in the 'QaQCPoints' table, so I tried:
var codes = _.flatten(_.pluck(JSONData.surveyGDB.table.tablename[1].record[0], "Code" ));
console.log(codes);
In the console, this returns an array with a length of 5, but with blank values.
What am I doing wrong?
I'd also rather search for the 'Code' values in the table based on something like the '#text' key value, instead of just using it's position in the object.
If I understood you correctly, you want to always search the record array within JSONData.surveyGDB.table.tablename array for some queries. This means you need to find the record based on some parameter and return something from the found record.
Do note that the record property is sometimes an array and sometimes an object (for table SurveyInfo) in your example so I'll assume you need to take this into account.
You can make a small function to extract data and handle both objects and arrays:
function extract(record, prop) {
if (Array.isArray(record)) {
return _.pluck(record, prop);
} else {
return record[prop];
}
}
Usage example:
I wanted all of the values for 'Code' in the 'QaQCPoints' table.
I'd also rather search for the 'Code' values in the table based on something like the '#text' key value, instead of just using it's position in the object.
To achieve this you first find a record using _.find, and then extract Code values from it using the method above:
var table = JSONData.surveyGDB.table.tablename;
// find an item that has `#text` property equal to `QaQcPoints`
var item = _.find(table, function(r) {
return r['#text'] === 'QaQcPoints';
});
// extract codes from the found item's record property
var code = extract(item.record, 'Code');
// output ["tp", "tb", "to", "bl", "bf"]
Running sample:
var JSONData = {
"surveyGDB": {
"filename": "..\\Topo\\SurveyGeoDatabase.gdb",
"table": {
"tablename": [{
"#text": "SurveyInfo",
"record": {
"OBJECTID": "1",
"SiteID": "CBW05583-345970",
"Watershed": "John Day",
"VisitType": "Initial visit",
"SurveyInstrument": "Total Station",
"ImportDate": "2015-07-22T09:08:42",
"StreamName": "Duncan Creek",
"InstrumentModel": "TopCon Magnet v2.5.1",
"FieldSeason": "2015"
}
}, {
"#text": "QaQcPoints",
"record": [{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tp",
"Count": "357"
}, {
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tb",
"Count": "92"
}, {
"OBJECTID": "3",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "to",
"Count": "8"
}, {
"OBJECTID": "4",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bl",
"Count": "279"
}, {
"OBJECTID": "5",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bf",
"Count": "18"
}]
}, {
"#text": "QaQcPolygons",
"record": [{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:43:08",
"SurveyExtentCount": "",
"WaterExtentCount": "",
"ChannelUnitsCount": "",
"ChannelUnitsUnique": ""
}, {
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T13:35:15",
"SurveyExtentCount": "1",
"WaterExtentCount": "1",
"ChannelUnitsCount": "21",
"ChannelUnitsUnique": "21"
}]
}]
}
}
}
function extract(record, prop) {
if (Array.isArray(record)) {
return _.pluck(record, prop);
} else {
return record[prop];
}
}
var table = JSONData.surveyGDB.table.tablename;
var item = _.find(table, function(r) {
return r['#text'] === 'QaQcPoints';
});
console.dir(item);
var code = extract(item.record, 'Code');
console.log(code);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
You have a two stage problem. Stage one is figuring out which table is QaQcPoints. If that's always JSONData.surveyGDB.table.tablename[1], you're good.
The next stage is getting your data out. You can use native array manipulation most of the time (unless you're on really old browsers). So:
var table = JSONData.surveyGDB.table.tablename[1].record;
var codeArray = table.map(function(val) { return val.Code; });
Will do the trick.
I asked this question here:
Working With Dynamic Multidimensional key-value pairs in JSON
But it's become a bit more involved and I can't get where I'm going from that answer. If I have a data object that looks like this:
{
"email": "user#someco.com",
"firstname": "Bob",
"lastname": "Smith",
"company": "ACME",
"custom": {
"services": [
{
"name": "svc1",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc2",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc3",
"desc": "abcdefg",
"selected": "false",
"status": "None"
},
{
"name": "svc4",
"desc": "abcdefg",
"selected": "false",
"status": "None"
}
],
"fields": [
{
"name": "Products",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Product1",
"desc": "abcdef"
},
{
"name": "Product2",
"desc": "abcdef"
}
],
"services": [
"svc1",
"svc2",
"svc3"
]
},
{
"name": "Wines",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Wine 1",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
},
{
"name": "Fruits",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Fruit 1",
"desc": "abcdef"
},
{
"name": "Fruit 2",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
}
]
}
};
How can I convert that into an Angular menu? The menu would need to list all of the services, and then if the service has an associated item in "fields" that item should be listed underneath it. So for instance "svc1" and its description should be listed on a line (got that working) but then "Product1" and "Product2" with their descriptions should appear on the next two lines because you can see that "svc1" is listed in the "services" field for "Products." Similarly, "svc4" should appear on a line, and then "Wines" and its description on the next line because "svc4" appears in the "services" field of "Wines."
I think the best way is to unpack and re-pack this JSON object in sequential order in the Angular controller and then push this data out to the Angular view but there might be a solution using only the logic available from the view. I've tried a bunch of nested fors and ifs along these lines (very much not working):
var i, j;
var listArray = [];
for (i = 0; i < $scope.svcs.length; i++) {
var littleArray = [$scope.svcs[i].status, $scope.svcs[i].name, $scope.svcs.desc];
listArray.push[littleArray1];
for (j=0; j < $scope.jFA.length; j++) {
if ($scope.jFA[j] == $scope.svcs[i].name) {
if ($scope.jFA[j] == $scope.svcs[i].fields)
littleArray = [$scope.jFA[j].fields] //...etc
}
}
...but that logic just keeps getting more and more dense and isn't working no matter now I try to use it. I liked the simplicity in the answer to the other question but have not had success in replicating it.
So if someone can help me figure out how to get the data into the right sequence using JS I can handle the Angular part. Or if you're an Angular whiz and have an answer along those lines, even better.
So it was a little hard understanding your question, but I gave it my best shot. Does this fiddle show what you are trying to achieve? http://jsfiddle.net/arknr6qz/1/
JS:
var app = angular.module('TestApp',[]);
app.controller('TestController', function($scope)
{
$scope.checkService = function(service, fieldServices)
{
if (fieldServices.indexOf(service) != -1) return true;
return false;
};
$scope.data = {
"email": "user#someco.com",
"firstname": "Bob",
"lastname": "Smith",
"company": "ACME",
"custom": {
"services": [
{
"name": "svc1",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc2",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc3",
"desc": "abcdefg",
"selected": "false",
"status": "None"
},
{
"name": "svc4",
"desc": "abcdefg",
"selected": "false",
"status": "None"
}
],
"fields": [
{
"name": "Products",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Product1",
"desc": "abcdef"
},
{
"name": "Product2",
"desc": "abcdef"
}
],
"services": [
"svc1",
"svc2",
"svc3"
]
},
{
"name": "Wines",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Wine 1",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
},
{
"name": "Fruits",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Fruit 1",
"desc": "abcdef"
},
{
"name": "Fruit 2",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
}
]
}
};
});
HTML:
<div ng-app="TestApp">
<div ng-controller="TestController">
<div ng-repeat="service in data.custom.services">
{{ service.name }}
<div class="indent" ng-repeat="fields in data.custom.fields">
<span ng-if="checkService(service.name, fields.services)">
{{fields.services.values}}
<span ng-repeat="value in fields.values">
{{value.name}} - {{value.desc}}<br>
</span>
</span>
</div>
</div>
</div>
</div>
and finally css:
.indent {
margin-left:10px;
}
Having a thorny problem and only see similar but also simpler solutions on SO.
Is is possible to generate a dynamic key AND dynamic values using JS/JSON?
For instance, let's say I have JSON like this:
{
"email": "user#someco.com",
"firstname": "Bob",
"lastname": "Smith",
"company": "ACME",
"custom": {
"services": [
{
"name": "svc1",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc2",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc3",
"desc": "abcdefg",
"selected": "false",
"status": "None"
},
{
"name": "svc4",
"desc": "abcdefg",
"selected": "false",
"status": "None"
}
],
"fields": [
{
"name": "Products",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Product1",
"desc": "abcdef"
},
{
"name": "Product2",
"desc": "abcdef"
}
],
"services": [
"svc1",
"svc2",
"svc3"
]
},
{
"name": "Wines",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Wine 1",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
},
{
"name": "Fruits",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Fruit 1",
"desc": "abcdef"
},
{
"name": "Fruit 2",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
}
]
}
};
I need to go into the fields and for each field (products, wines, fruits) see if a given service is contained within so that I can go back and generate a product or wine or fruit for each service that requires it. But I don't want to repeat the services names more than once. The resulting JSON should look something like this:
{"svc1":["Products"], "svc2":["Products"], "svc3":["Products"], "svc4":["Fruits", "Wines"]}
The hope would be that to generate a dynamic list in Angular I can just turn and loop back through this JSON, pulling out the values for each product, fruit, wine, whatever.
I've been trying a lot of nested for loops and the like but whenever I get more than one layer down the dynamism seems to stop. I'm guessing that for this to work I need to move between JS Objects and JSON?
Right now I'm trying something like this, which isn't quite working, stringify or no. And maybe I'm flip-flopping too much between JSON and JS Objects:
var outObj = [];
var fieldItems;
$.each(jsonObj.custom.fields, function(key, item) {
fieldItems = item;
fieldItems.name = item.name;
$.each(fieldItems.services, function(key, item) {
var serviceName = item;
//check to see if the serviceName already exists
if (outObj.indexOf(serviceName) > -1) {
outObj.serviceName.push(fieldItems.name);
} else {
outObj.push(serviceName);
}
});
});
JSON.stringify(outObj);
console.log("outObj " + outObj);
I get "can't read property 'push' of undefined" errors and the like. Seems this should be possible from a single nested loop, but maybe I need to just do two passes? Any other suggestions?
To me it sounds like overcomplicated solution. You can use basic array methods of javascript to filter out required structure. I am not sure what profiling_value in the presented snippet, so I started from the object structure in OP
var desiredResult = jsonObj.custom.services.reduce(function(result, service){
result[service.name] = jsonObj.custom.fields.filter(function(field){
return field.services.indexOf(service.name) >= 0;
}).map(function(field){ return field.name; });
return result;
}, {});
This gives the expected result for mentioned object.
reduce is required to iterate over all services and accumulate result in one object. Then for each service fields are iterated to filter out only those that contain link to this service. And finally list of filtered fields is transformed (map) into list of strings - their names - and inserted into accumulator
I've this json return
{
"timeline": [{
"id": "2",
"self": {
"uid": "2",
"username": "ptamzz"
},
"file": {
"fid": "43",
"file_name": "First Name"
},
"connection": {
"fid": "4",
"username": "tom"
},
"action": "viewed your document",
"time": "2012-01-16 12:23:03",
"tags": ["Engineering", "Computer Science", "Java", "Java Library"]
}, {
"id": "1",
"self": {
"uid": "2",
"username": "ptamzz"
},
"file": {
"fid": "41",
"file_name": "Write Up"
},
"connection": {
"fid": "4",
"username": "tom"
},
"action": "favorited your document",
"time": "2012-01-16 12:22:04",
"tags": ["Design"]
}]
}
According to the tutorial at http://coenraets.org/blog/2011/12/tutorial-html-templates-with-mustache-js/ (Sample 6: Nested Object section), you can access dot notation to access the nested objects.
From the above json, I want to retrieve the data like self.username, file.file_name etc etc.
Now, I've my template as
{{#timeline}}
<li>
{{self.username}}
</li>
{{/timeline}}
But self.username doesn't work.
How do I retrieve these nested values?
I don't think it's the right way to do but since I couldn't find any answers here, I figured out something myself. At least this works.
{{#timeline}}
<li>
{{#self}}{{username}}{{/self}}
</li>
{{/timeline}}
Dot notation does not work on version 0.4x and below. It worked on "0.7.2".