JSON get a value if another value - javascript

Okay so my JSON is something along the lines of:
{
"wares":[
{
"id":"1",
"name":"apples",
"stock":"40",
},
{
"id":"2",
"name":"pears",
"stock":"40",
},
{
"id":"3",
"name":"bananas",
"stock":"30",
}
]
}
So I would like to get the name if the stock is 40, I've used this code as an example, which I found here: http://techslides.com/how-to-parse-and-search-json-in-javascript/
function getObjects(obj, key, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getObjects(obj[i], key, val));
} else
//if key matches and value matches or if key matches and value is not passed (eliminating the case where key matches but passed value does not)
if (i == key && obj[i] == val || i == key && val == '') { //
objects.push(obj);
} else if (obj[i] == val && key == ''){
//only add if the object is not already in the array
if (objects.lastIndexOf(obj) == -1){
objects.push(obj);
}
}
}
return objects;
}
which works, but I haven't quite found a way to return the name if the stock is 40.
I was thinking you put an extra value in the function called ret (return) as in what it should return. Something along the lines of
alert(JSON.stringify(getObjects(JSON, 'stock', '40', 'name')));
Thanks a lot!

An alternate solution using the native filter() and map() methods:
function getObjects(_object, _key, _value, _return) {
return _object.filter(function(_item) {
return _item[_key] == _value;
}).map(function(_item) {
return _item[_return];
});
}
Note that in the above call, we need to pass the array containing the items, not the root object. Or you can modify the above to accept the root object
And you call it like:
getObjects(obj.wares, 'stock', 40, 'name');
to get back ["apples", "pears"]

Try this out!
$.each(getObjects(JSON, "stock", "40"), function() {
alert(this.name);
})
EDIT: Just in order to explain what I wrote, the getObjects function returns all the objects that matches the search criteria, so then what I did was to get each name of all the JSONS that are returned

Related

hasOwnProperty(propName) vs. hasOwnProperty("propName")

I've worked through the challenge at Record Collection and have a working solution.
When and why do we add quotes ("" or '') inside the propName for hasOwnProperty(propName)? When would you use hasOwnProperty(propName) or hasOwnProperty("propName")?
Here is my functioning solution:
function updateRecords(id, prop, value) {
if (prop != "tracks" && value != "") {
collection[id][prop] = value;
}
else if (prop === "tracks" && collection[id].hasOwnProperty("tracks") === false) {
collection[id].tracks = [];
collection[id].tracks.push(value);
}
else if (prop ==="tracks" && value != ""){
collection[id].tracks.push(value);
}
else if (value === "") {
delete collection[id][prop];
}
return collection;
}
but if hasOwnProperty("tracks") is changed to hasOwnProperty(tracks) the code stops working. This confuses me as the only example I was shown for hasOwnProperty(propName) did not use quotes, and fails if quotes are used around propName.
I learned about hasOwnProperty() from: Testing object for Properties.
In most situations, you want to be using a string to check if the property exists on the object. In cases where quotes aren't used, this would mean that it would have to be a variable which holds the value of a string corresponding to a property name - it has nothing to do with the variable being named the same way as the property. For example you may see some code like this where they iterate over the properties and check if the property belongs to the object (example taken from docs on Object.prototype.hasOwnProperty):
var buz = {
fog: 'stack'
};
for (var name in buz) {
if (buz.hasOwnProperty(name)) { // here, name holds the value of the property
console.log('this is fog (' +
name + ') for sure. Value: ' + buz[name]);
}
else {
console.log(name); // toString or something else
}
}
As #Gavin mentioned, the example shown is just trying to tell you that you can pass the name of the property as a string in place of propname

Find and remove empty properties from objects

This is my array of objects:
var data = [
{
"label": "HOME",
"href": "web-tutor99.com",
"children": [{}]
},
{
"href": "web-tutor99.com",
"label": "HTML5"
}
];
It is a multidimensional object and here the children property is empty. How can I find empty properties like this and remove them using jQuery?
Try this
data = [{
"label": "HOME",
"href": "web-tutor99.com",
"children": [{}]
}, {
"href": "web-tutor99.com",
"label": "HTML5"
}];
alert("Before : "+JSON.stringify(data));
//console.log(data);
checkEmptyObj(data);
alert("After : "+JSON.stringify(data));
function checkEmptyObj(data) {
$.each(data, function(key, value) {
if ($.isPlainObject(value) || $.isArray(value)) {
checkEmptyObj(value);
}
//alert(key+":"+$.isEmptyObject(value));
if (value === "" || value === null || $.isEmptyObject(value)) {
delete data[key];
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You could do this..
for (var i in data) {
if (test[i].children === null || test[i].children === undefined || test[i].children.length<=0) {
delete test[i].children;
}
}
But I see no practical use in wasting CPU cycles looping through objects to remove empty objects.
Not really sure what you're trying to achieve. But you're better off just checking if its empty, and then not displaying if its the case.
You could simply create a (if nested, recursive) function looping through all elements and check if the it has a value, if not, delete that property.
In your example object you have the problem that the children property is by far not empty - it is a property with a value of an array containing one empty object. Depending on your scenario you'd have to run through your object multiple times, removing empty entries step by step (could probably do some optimization).
As a final note, you can use for...in to loop through an object's properties and for...of to loop through an object's/array's values.
I think the following pure JS snippet takes care of the job. You can check it # JSBin
var data = [{"label":"HOME","href":"web-tutor99.com","children":[{}]},{"href":"web-tutor99.com","label":"HTML5"}];
function walkJSONObj(obj){
for (var prop in obj) {
if (obj[prop].constructor === Array) { //if prop is an array
walkJSONArray(obj[prop]); //go walk through the arrays
obj[prop].length === 0 && delete obj[prop]; //if on return the array is empty delete it
}
else typeof obj[prop] === 'undefined' && delete obj[prop]; //delete undefined props
}
}
function walkJSONArray(arr){
for (var l = arr.length-1; l >= 0; l--) {
walkJSONObj(arr[l]); // go walk the item objects
if (Object.keys(arr[l]).length === 0 && JSON.stringify(arr[l]) === JSON.stringify({})) {
arr.splice(l, 1); // if on return the object is empty delete it
}
}
}
walkJSONArray(data);

How do I get JSON data from one HTML Apps Script file in another HTML file?

I have some data in a file called data.json.html in an Apps Script project that I would like to access from JavaScript. The file looks like this:
<script>
var data = {"book1":{"1":25, "2":17}, "book2":{"1":37, "2":4, "3":12}};
</script>
I have tried to access this data by the following means:
Attempt #1
<script type="text/javascript" src="data.json"></script>
<script>
var books = JSON.parse(data);
</script>
Attempt #2
<?!= include("data.json") ?>
<script>
var books = JSON.parse(data);
</script>
Neither one of these worked. Can anyone tell me the correct way of doing this?
Edit: Sorry I forgot to include information about what "it doesn't work" means. Basically, the data doesn't make it into the variable, it's supposed to go into, and there's no error telling me what happened in the execution transcript.
If anyone wants to look at the full script, it is embedded in the Google Doc here. Just go to Tools > Script editor... to find it.
This may not be optimum but it will work.
Depending whether the html file is on your domain (then just simply access it) otherwise retrieve the data by an HTTP request. Then use this to find the son location and its length:
var string = "responseString",
substring = "book1";
var jsonStr = str.substring(string.indexOf(substring), 100);
This can be used if you know for example the length is 100 from the matching book1. If you don't know the length use something like above ton find location of "};".
Then use jsonStr in the following to get the key values.
//return an array of objects according to key, value, or key and value matching
function getObjects(obj, key, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getObjects(obj[i], key, val));
} else
//if key matches and value matches or if key matches and value is not passed (eliminating the case where key matches but passed value does not)
if (i == key && obj[i] == val || i == key && val == '') { //
objects.push(obj);
} else if (obj[i] == val && key == ''){
//only add if the object is not already in the array
if (objects.lastIndexOf(obj) == -1){
objects.push(obj);
}
}
}
return objects;
}
//return an array of values that match on a certain key
function getValues(obj, key) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getValues(obj[i], key));
} else if (i == key) {
objects.push(obj[i]);
}
}
return objects;
}
//return an array of keys that match on a certain value
function getKeys(obj, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getKeys(obj[i], val));
} else if (obj[i] == val) {
objects.push(i);
}
}
return objects;
}
var json = '{"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","ID":"44","str":"SGML","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}}}}';
var js = JSON.parse(json);
//example of grabbing objects that match some key and value in JSON
console.log(getObjects(js,'ID','SGML'));
//returns 1 object where a key names ID has the value SGML
//example of grabbing objects that match some key in JSON
console.log(getObjects(js,'ID',''));
//returns 2 objects since keys with name ID are found in 2 objects
//example of grabbing obejcts that match some value in JSON
console.log(getObjects(js,'','SGML'));
//returns 2 object since 2 obects have keys with the value SGML
//example of grabbing objects that match some key in JSON
console.log(getObjects(js,'ID',''));
//returns 2 objects since keys with name ID are found in 2 objects
//example of grabbing values from any key passed in JSON
console.log(getValues(js,'ID'));
//returns array ["SGML", "44"]
//example of grabbing keys by searching via values in JSON
console.log(getKeys(js,'SGML'));
//returns array ["ID", "SortAs", "Acronym", "str"]
In that case you can use this to access a local file:
function readTextFile(file)
{
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, false);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
{
if(rawFile.status === 200 || rawFile.status == 0)
{
var allText = rawFile.responseText;
alert(allText);
}
}
}
rawFile.send(null);
}
and file in the first line will be the path and file name.

Looping though unique keys

I have a json object which I would like to loop through; however each object has a nested object which I can't access through dot notation due to the values being unique.
.__proto__
will give me consistent results; however I'd like to pull out the values starting with the "-Jg". Is it possible to do this through a regular expression or another method?
Edit:
I'm looping through the 'javascript object' with angular
var lognew = [];
angular.forEach(log, function(value, key) {
if(value){
if(value.substr(0,3) !== "-Jg" ){
this.push(value);
}
}
}, lognew);
console.log(lognew);
This currently returns:
TypeError: undefined is not a function
Just enumerate using for in and look at the first 3 characters of the object's key
for(var key in jsonObj){
if( key.substr(0,3) !== "-Jg" ) continue;
var nestedObject = jsonObj[key];
}
angular edit
var log = { "1": { "-Jga": "b" }, "2": { "-Jgc": "d" } };
var lognew = [];
angular.forEach(log, function(value, key) {
if(key){
if(key.substr(0,3) !== "-Jg" ){
this.push(value);
}
}
}, lognew);
console.log(lognew);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

javascript find parent of array item

I have an array item like this:
var array = USA.NY[2];
// gives "Albany"
{"USA" : {
"NY" : ["New York City", "Long Island", "Albany"]
}}
I want to find the state from just having the array. How do I do this? Thanks.
function findParent(array) {
// do something
// return NY
}
In Javascript, array elements have no reference to the array(s) containing them.
To achieve this, you will have to have a reference to the 'root' array, which will depend on your data model.
Assuming USA is accessible, and contains only arrays, you could do this:
function findParent(item) {
var member, i, array;
for (member in USA) {
if (USA.hasOwnProperty(member) && typeof USA[member] === 'object' && USA[member] instanceof Array) {
array = USA[member];
for(i = 0; i < array.length; i += 1) {
if (array[i] === item) {
return array;
}
}
}
}
}
Note that I’ve renamed the array parameter to item since you’re passing along a value (and array item), and you expect the array to be returned.
If you want to know the name of the array, you should return member instead.
Here is a generic function that can be used to find the parent key of any kind of multi-dimentional object. I use underscore.js by habit and for conciseness to abstract array vs associative array loops.
(function (root, struct) {
var parent = null;
var check = function (root, struct) {
_.each(root, function (value, key) {
if (value == struct) {
parent = key;
} else if (root == struct) {
parent = '_root';
} else if (typeof value === 'object') {
check(value, struct);
}
});
}
check(root, struct);
return parent;
})

Categories

Resources