JSON Object get length - javascript

I have nested JSON which is as following:
var data = [
{
"id":"4",
"name":"2nd anniversary",
"date":"2015-12-17",
"location":"Mumbai",
"story_body":"Gzjjs jdk djks jdks jdkd jx djdb djd JD djbd djdj d",
"short_link":"izWfs",
"created_at":"2015-12-11 03:49:52",
"path":[
"\/SupportData\/ImpalzB2B\/uploads\/711453354154623.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/90294930451449759544217.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/471453355023537.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/90294930451449759544223.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/90294930451449759544179.jpg"
],
"update_type":"3"
},
{
"id":"7",
"name":"#1styearAnniversary",
"date":"2016-01-20",
"location":"Mumbai",
"story_body":"Bsjsj jdkdk djdkdk dkdkf kdkf dkfj fjfj fjfkjdd djkd",
"short_link":"FHXh0",
"created_at":"2016-01-20 23:10:54",
"path":"\/SupportData\/ImpalzB2B\/uploads\/11453356652175.jpg",
"update_type":"3"
},
{
"id":"19",
"name":"Product qetyfvhchv",
"description":"Cheers Vgdhvjd hugging",
"short_link":"jPE7G",
"created_at":"2016-01-18 05:03:46",
"path":"\/SupportData\/ImpalzB2B\/uploads\/90294930451453118625255.jpg",
"update_type":"4"
},
{
"id":"20",
"name":"F frfgcgj ggvvhv",
"description":" Vdhsj fgjjchk",
"short_link":"hMn8K",
"created_at":"2016-01-18 05:04:16",
"path":"\/SupportData\/ImpalzB2B\/uploads\/90294930451453118654785.jpg",
"update_type":"4"
},
{
"id":"25",
"name":"Gshsh djdj djdkd dkkd",
"description":"Bsjjd djjd djdirj dudir",
"short_link":"dhT6l",
"created_at":"2016-01-22 05:39:31",
"path":[
"\/SupportData\/ImpalzB2B\/uploads\/11453466369930.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/11453466369891.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/11453466369942.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/11453466369934.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/11453466369939.jpg"
],
"update_type":"4"
},
{
"id":"26",
"name":"For Healthy Breakfast, head over to our new restaurant in Andheri",
"description":"Delightful upma",
"short_link":"CG0i4",
"created_at":"2016-02-04 06:58:17",
"path":"\/SupportData\/ImpalzB2B\/uploads\/11454594295456.jpg",
"update_type":"4"
},
{
"id":"1",
"body":"#Awesome2Eat",
"votes":"28",
"update_type":"7",
"short_link":"GcKAe",
"created_at":"2016-02-04 01:28:53",
"name":"nehil"
},
{
"id":"10",
"body":"#Bouncy",
"votes":"1",
"update_type":"7",
"short_link":"JXUxz",
"created_at":"2016-02-04 00:12:52",
"name":"nehil"
},
{
"id":"11",
"body":"#Superman",
"votes":"0",
"update_type":"7",
"short_link":"4Keyd",
"created_at":"2016-02-04 01:17:36",
"name":"nehil"
}
]
How do I get lenght of path array from Object?
I tried which gives wrong length.
for (var key in data) {
if(data[key].update_type == '3'){
console.log(data[key].path.length); // 5 and 49 . It Should be 5 and 1
}
};
Also Is this the right way to get each element of Object? :
for (var key in data) {
console.log(data[key].id);
$.each(data[key].path, function (i, obj) {
console.log(obj);
});
};
Fiddle link: http://jsfiddle.net/Nehil/2ym3ffo0/

Because the type of value of data[key].path is not array (second instance), it is a String. And String also has the length attribute which gives the length of string.
make it
for (var key in data) {
if(data[key].update_type == '3')
{
if (typeof data[key].path == "string" )
{
console.log( 1 );
}
else
{
console.log(data[key].path.length); // 5 and 49 . It Should be 5 and 1
//to print all the elements on the console one by one
if ( data[key].path && data[key].path.length > 0 )
{
data[key].path.forEach( function(value){
console.log( value );
} );
}
}
}
}

You can use forEach loop:
The forEach() method executes a provided function once per array
element.
var data = [{
"id": "4",
"name": "2nd anniversary",
"date": "2015-12-17",
"location": "Mumbai",
"story_body": "Gzjjs jdk djks jdks jdkd jx djdb djd JD djbd djdj d",
"short_link": "izWfs",
"created_at": "2015-12-11 03:49:52",
"path": [
"\/SupportData\/ImpalzB2B\/uploads\/711453354154623.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/90294930451449759544217.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/471453355023537.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/90294930451449759544223.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/90294930451449759544179.jpg"
],
"update_type": "3"
}, {
"id": "7",
"name": "#1styearAnniversary",
"date": "2016-01-20",
"location": "Mumbai",
"story_body": "Bsjsj jdkdk djdkdk dkdkf kdkf dkfj fjfj fjfkjdd djkd",
"short_link": "FHXh0",
"created_at": "2016-01-20 23:10:54",
"path": "\/SupportData\/ImpalzB2B\/uploads\/11453356652175.jpg",
"update_type": "3"
}, {
"id": "19",
"name": "Product qetyfvhchv",
"description": "Cheers Vgdhvjd hugging",
"short_link": "jPE7G",
"created_at": "2016-01-18 05:03:46",
"path": "\/SupportData\/ImpalzB2B\/uploads\/90294930451453118625255.jpg",
"update_type": "4"
}, {
"id": "20",
"name": "F frfgcgj ggvvhv",
"description": " Vdhsj fgjjchk",
"short_link": "hMn8K",
"created_at": "2016-01-18 05:04:16",
"path": "\/SupportData\/ImpalzB2B\/uploads\/90294930451453118654785.jpg",
"update_type": "4"
}, {
"id": "25",
"name": "Gshsh djdj djdkd dkkd",
"description": "Bsjjd djjd djdirj dudir",
"short_link": "dhT6l",
"created_at": "2016-01-22 05:39:31",
"path": [
"\/SupportData\/ImpalzB2B\/uploads\/11453466369930.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/11453466369891.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/11453466369942.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/11453466369934.jpg",
"\/SupportData\/ImpalzB2B\/uploads\/11453466369939.jpg"
],
"update_type": "4"
}, {
"id": "26",
"name": "For Healthy Breakfast, head over to our new restaurant in Andheri",
"description": "Delightful upma",
"short_link": "CG0i4",
"created_at": "2016-02-04 06:58:17",
"path": "\/SupportData\/ImpalzB2B\/uploads\/11454594295456.jpg",
"update_type": "4"
}, {
"id": "1",
"body": "#Awesome2Eat",
"votes": "28",
"update_type": "7",
"short_link": "GcKAe",
"created_at": "2016-02-04 01:28:53",
"name": "nehil"
}, {
"id": "10",
"body": "#Bouncy",
"votes": "1",
"update_type": "7",
"short_link": "JXUxz",
"created_at": "2016-02-04 00:12:52",
"name": "nehil"
}, {
"id": "11",
"body": "#Superman",
"votes": "0",
"update_type": "7",
"short_link": "4Keyd",
"created_at": "2016-02-04 01:17:36",
"name": "nehil"
}]
data.forEach((a) => { /*ES6 Arrow funtion. can use simple 'function(){}' too*/
if (typeof a.path == "string") {
console.log(1);
} else if(typeof a.path!=='undefined') {
console.log(a.path.length);
}else{
console.log(-1);
}
})

repeatedly throughout this answer I use this code:
var path = (item.path && typeof item.path == 'string' ? [item.path] : item.path) || [];
breaking it down, if item.path is truthy, if it's a string, set it to [item.path] (i.e. an array with a single element == item.path), othewise use item.path
if this results in a falsey value (item.path is undefined or null etc) set path = [] an empty array
Now path will always be an array, so .length/.forEach/$.each will work without any issue (except if item.path is something other that string/array/undefined/null of course)
as you already use jquery.each, you could do this
$.each(data, function(i, item) {
if (item.update_type == '3') {
var path = (item.path && typeof item.path == 'string' ? [item.path] : item.path) || [];
console.log(path.length);
}
});
and
$.each(data, function(i, item) {
console.log(item.id);
var path = (item.path && typeof item.path == 'string' ? [item.path] : item.path) || [];
$.each(path, function (i, obj) {
console.log(obj);
});
});
I prefer to use jquery as little as possible
data.forEach(function (item) {
if (item.update_type == '3') {
var path = (item.path && typeof item.path == 'string' ? [item.path] : item.path) || [];
console.log(path.length);
}
});
and
data.forEach(function (item) {
console.log(item.id);
var path = (item.path && typeof item.path == 'string' ? [item.path] : item.path) || [];
path.forEach(function (obj) {
console.log(obj);
});
});
to use forEach you may need this polyfill if you think you may need to support IE8 or less

This is my solution using UnderscoreJs:
_.each(data, function(item) {
if (item['update_type'] != '3') return;
var path = (_.isString(item.path) ? [item.path] : item.path) || [];
var pathCount = path.length;
// Log path count for item.
pathCount && console.log(pathCount);
// Or log path list for item.
pathCount && _.each(path, function(pathStr) { console.log(pathStr); });
});

Related

javascript recursive function giving error

I have my JSON structured like below which has the next and previous properties of an array of keys from the same structure.
{
"e6e1de44-d53b-44ae-9d52-8f6e1358f8ec": {
"course": "Semester 1",
"status": "completed",
"next": [
"d1fc647b-ad7e-4b72-9269-5559948ee61d"
],
"previous": [],
},
"d1fc647b-ad7e-4b72-9269-5559948ee61d": {
"course": "Semester 2",
"status": "completed",
"next": [
"cb00b200-cee3-4ab8-af11-abb7ea26183b",
"7b958370-d697-4536-9bff-fa564a5688ef"
],
"previous": [
"e6e1de44-d53b-44ae-9d52-8f6e1358f8ec"
],
},
"cb00b200-cee3-4ab8-af11-abb7ea26183b": {
"course": "Semester 3",
"status": "active",
"next": [
"72488692-064c-436c-93cb-8ebe2be7e168"
],
"previous": [
"d1fc647b-ad7e-4b72-9269-5559948ee61d"
],
},
"7b958370-d697-4536-9bff-fa564a5688ef": {
"course": "Semester 4",
"status": "active",
"next": [
"72488692-064c-436c-93cb-8ebe2be7e168"
],
"previous": [
"d1fc647b-ad7e-4b72-9269-5559948ee61d"
],
},
"72488692-064c-436c-93cb-8ebe2be7e168": {
"course": "Final",
"status": "not-started",
"next": [],
"previous": [
"cb00b200-cee3-4ab8-af11-abb7ea26183b",
"7b958370-d697-4536-9bff-fa564a5688ef"
],
}
}
I am trying to get the next array and the previous array recursively but it is giving me an error TypeError: Cannot read properties of undefined (reading 'recursiveFunc') I'm calling a function like this.
let nextRes = [];
recursiveFunc(courseData, 'e6e1de44-d53b-44ae-9d52-8f6e1358f8ec', nextRes, true);
let prevRes = [];
recursiveFunc(courseData, 'cb00b200-cee3-4ab8-af11-abb7ea26183b', prevRes, false);
I was wondering if the same function could be used to achieve a similar result. It is just a matter of traversing forward or backward. How can I get the id of the next data recursively?
nextRes shuld have populated ['d1fc647b-ad7e-4b72-9269-5559948ee61d', 'cb00b200-cee3-4ab8-af11-abb7ea26183b', '7b958370-d697-4536-9bff-fa564a5688ef', '72488692-064c-436c-93cb-8ebe2be7e168'] and prevRes like ['d1fc647b-ad7e-4b72-9269-5559948ee61d', 'e6e1de44-d53b-44ae-9d52-8f6e1358f8ec']
function recursiveFunc(data, parId, acc, forward) {
for (let property in data) {
if (data.hasOwnProperty(property) && typeof data[property] === 'object') {
var current = data[property];
if (forward && property == parId && typeof current.preReqStages === 'object' && data[property].next.length > 0) {
acc.push(current.next);
} else if (!forward && property == parId && typeof current.preReqStages === 'object' && data[property].previous.length > 0) {
acc.push(current.previous);
} else {
this.recursiveFunc(data, property, acc, forward)
}
}
}
}
Starting in order of your code, first you don't need to validate data.hasOwnProperty(property) if you're making a for of the properties in data.
Second, your validation of typeof current.preReqStages === 'object' should be typeof current.next === 'object' or current.previous for the next if, since you don't have a value of preReqStages.
Then, you are adding current.next to your array, meaning you're adding an array inside an array, when you only want the value, so I added a forEach and added each value.
And then the recursion should be inside the matches, because what you want to get is all the chain of courses, meaning that when you get the next one, you need to get the next one of that new property. So I made the recursion inside the forEach.
Here's the final result:
const courseData = {
"e6e1de44-d53b-44ae-9d52-8f6e1358f8ec": {
"course": "Semester 1",
"status": "completed",
"next": [
"d1fc647b-ad7e-4b72-9269-5559948ee61d"
],
"previous": [],
},
"d1fc647b-ad7e-4b72-9269-5559948ee61d": {
"course": "Semester 2",
"status": "completed",
"next": [
"cb00b200-cee3-4ab8-af11-abb7ea26183b",
"7b958370-d697-4536-9bff-fa564a5688ef"
],
"previous": [
"e6e1de44-d53b-44ae-9d52-8f6e1358f8ec"
],
},
"cb00b200-cee3-4ab8-af11-abb7ea26183b": {
"course": "Semester 3",
"status": "active",
"next": [
"72488692-064c-436c-93cb-8ebe2be7e168"
],
"previous": [
"d1fc647b-ad7e-4b72-9269-5559948ee61d"
],
},
"7b958370-d697-4536-9bff-fa564a5688ef": {
"course": "Semester 4",
"status": "active",
"next": [
"72488692-064c-436c-93cb-8ebe2be7e168"
],
"previous": [
"d1fc647b-ad7e-4b72-9269-5559948ee61d"
],
},
"72488692-064c-436c-93cb-8ebe2be7e168": {
"course": "Final",
"status": "not-started",
"next": [],
"previous": [
"cb00b200-cee3-4ab8-af11-abb7ea26183b",
"7b958370-d697-4536-9bff-fa564a5688ef"
],
}
}
function recursiveFunc(data, parId, acc, forward) {
for (let property in data) {
if (typeof data[property] === 'object') {
var current = data[property];
if (forward && property == parId && typeof current.next === 'object' && current.next.length > 0) {
current.next.forEach(n => {
if (!acc.includes(n)) {
acc.push(n)
this.recursiveFunc(data, n, acc, forward)
}
});
} else if (!forward && property == parId && typeof current.previous === 'object' && current.previous.length > 0) {
current.previous.forEach(p => {
if (!acc.includes(p)) {
acc.push(p)
this.recursiveFunc(data, p, acc, forward)
}
});
}
}
}
}
let nextRes = [];
recursiveFunc(courseData, 'e6e1de44-d53b-44ae-9d52-8f6e1358f8ec', nextRes, true);
console.log(nextRes)
let prevRes = [];
recursiveFunc(courseData, 'cb00b200-cee3-4ab8-af11-abb7ea26183b', prevRes, false);
console.log(prevRes)

How to get the key value from nested object

I am having below object where I am trying to get all the id values.
[{
"type": "test",
"id": "100",
"values": {
"name": "Alpha"
},
"validations": []
}, {
"type": "services",
"validations": [{
"id": "200",
"name": "John",
"selection": [{
"id": "300",
"values": {
"name": "Blob"
}
}]
}]
}]
Using the below code, I am getting only the first id value. Is there any way to get all the id values from the nested object without using any external module.
for (var prop in obj) {
console.log(prop)
if (prop === key) {
set.push(prop);
}
}
Expected Output
[100,200,300] //all id values
You can use a JavaScript function like below to get the nested properties:
function findProp(obj, key, out) {
var i,
proto = Object.prototype,
ts = proto.toString,
hasOwn = proto.hasOwnProperty.bind(obj);
if ('[object Array]' !== ts.call(out)) out = [];
for (i in obj) {
if (hasOwn(i)) {
if (i === key) {
out.push(obj[i]);
} else if ('[object Array]' === ts.call(obj[i]) || '[object Object]' === ts.call(obj[i])) {
findProp(obj[i], key, out);
}
}
}
return out;
}
Check this Fiddle for a working solution.
Using Object.keys
function findProp(obj, prop) {
var result = [];
function recursivelyFindProp(o, keyToBeFound) {
Object.keys(o).forEach(function (key) {
if (typeof o[key] === 'object') {
recursivelyFindProp(o[key], keyToBeFound);
} else {
if (key === keyToBeFound) result.push(o[key]);
}
});
}
recursivelyFindProp(obj, prop);
return result;
}
// Testing:
var arr = [{
"type": "test",
"id": "100",
"values": {
"name": "Alpha"
},
"validations": []
}, {
"type": "services",
"validations": [{
"id": "200",
"name": "John",
"selection": [{
"id": "300",
"values": {
"name": "Blob"
}
}]
}]
}];
console.log(findProp(arr, "id"));
To get the keys from nested objects, you first need to put your code in a function, then for each of the top-level keys, check if it's an array or object. If it is, just call your function again from within that function (weird, I know.) Just make sure you don't skip the check of whether it's an object. You'll get stuck in an infinite loop. Something like this:
function parseObjectKeys(obj) {
for (var prop in obj) {
console.log(prop)
var sub = obj[prop]
if (typeof(sub) == "object") {
parseObjectKeys(sub);
}
}
}
Here's a more complex example:
https://jsfiddle.net/tfqLnzLm/1/
You can use a XPath styled json parser like JSONPath. The version I'm presenting here is a extended version I did here:
function jsonPath(obj,expr,arg){var P={resultType:arg&&arg.resultType||"VALUE",result:[],normalize:function(e){var t=[];return e.replace(/[\['](\??\(.*?\))[\]']/g,function(e,r){return"[#"+(t.push(r)-1)+"]"}).replace(/'?\.'?|\['?/g,";").replace(/;;;|;;/g,";..;").replace(/;$|'?\]|'$/g,"").replace(/#([0-9]+)/g,function(e,r){return t[r]})},asPath:function(e){for(var t=e.split(";"),r="$",a=1,n=t.length;n>a;a++)r+=/^[0-9*]+$/.test(t[a])?"["+t[a]+"]":"['"+t[a]+"']";return r},store:function(e,t){return e&&(P.result[P.result.length]="PATH"==P.resultType?P.asPath(e):t),!!e},trace:function(e,t,r){if(e){var a=e.split(";"),n=a.shift();if(a=a.join(";"),t&&t.hasOwnProperty(n))P.trace(a,t[n],r+";"+n);else if("*"===n)P.walk(n,a,t,r,function(e,t,r,a,n){P.trace(e+";"+r,a,n)});else if(".."===n)P.trace(a,t,r),P.walk(n,a,t,r,function(e,t,r,a,n){"object"==typeof a[e]&&P.trace("..;"+r,a[e],n+";"+e)});else if(/,/.test(n))for(var l=n.split(/'?,'?/),s=0,c=l.length;c>s;s++)P.trace(l[s]+";"+a,t,r);else/^\(.*?\)$/.test(n)?P.trace(P.eval(n,t,r.substr(r.lastIndexOf(";")+1))+";"+a,t,r):/^\?\(.*?\)$/.test(n)?P.walk(n,a,t,r,function(e,t,r,a,n){P.eval(t.replace(/^\?\((.*?)\)$/,"$1"),a[e],e)&&P.trace(e+";"+r,a,n)}):/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(n)&&P.slice(n,a,t,r)}else P.store(r,t)},walk:function(e,t,r,a,n){if(r instanceof Array)for(var l=0,s=r.length;s>l;l++)l in r&&n(l,e,t,r,a);else if("object"==typeof r)for(var c in r)r.hasOwnProperty(c)&&n(c,e,t,r,a)},slice:function(e,t,r,a){if(r instanceof Array){var n=r.length,l=0,s=n,c=1;e.replace(/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g,function(e,t,r,a){l=parseInt(t||l),s=parseInt(r||s),c=parseInt(a||c)}),l=0>l?Math.max(0,l+n):Math.min(n,l),s=0>s?Math.max(0,s+n):Math.min(n,s);for(var o=l;s>o;o+=c)P.trace(o+";"+t,r,a)}},eval:function(x,_v,_vname){try{return $&&_v&&eval(x.replace(/#/g,"_v"))}catch(e){throw new SyntaxError("jsonPath: "+e.message+": "+x.replace(/#/g,"_v").replace(/\^/g,"_a"))}}},$=obj;return expr&&obj&&("VALUE"==P.resultType||"PATH"==P.resultType)?(P.trace(P.normalize(expr).replace(/^\$;/,""),obj,"$"),P.result.length?P.result:!1):void 0}
// some extensions I have added to JSONPath
var jsonPathStore = function(obj,path,values) {
var maps=jsonPath(obj, path,{resultType:"PATH"})
maps.map(function(item,index) {
return eval( '(' + item.replace(/\$/,"obj") + '="' + values[index] +'"' + ')' );
})
}
var jsonPathDelete = function(obj,path) {
var maps=jsonPath(obj, path,{resultType:"PATH"})
maps.map(function(item,index) {
return eval( '(' + 'delete ' + item.replace(/\$/,"obj") + ')' );
})
}
var jsonPathRead = function(obj,path) {
var maps=jsonPath(obj, path,{resultType:"PATH"})
return maps.map(function(item,index) {
return eval( '(' + item.replace(/\$/,"obj") + ')' );
})
}
var jsonObject = [{
"type": "test",
"id": "100",
"values": {
"name": "Alpha"
},
"validations": []
}, {
"type": "services",
"validations": [{
"id": "200",
"name": "John",
"selection": [{
"id": "300",
"values": {
"name": "Blob"
}
}]
}]
}]
// this XPath will read all the id properties starting from the root element
console.log( "jsonPathRead All Ids" + JSON.stringify(jsonPathRead(jsonObject,"$..id"), null, 2) )
function getIds(obj) {
for (var x in obj) {
if (typeof obj[x] === 'object') {
getIds(obj[x]);
} else if (x === 'id') {
console.log(obj.id);
}
}
}

filter result using 2 JSON

This is my saved localstorage,
[{"industry_Id":1,"merchant_id":2}]
I want to filter below result, to get HP.
{
"industries": [
{
"id": 1,
"name": "oil and gas",
"merchant": [
{
"id": 1,
"name": "ABC",
},
{
"id": 2,
"name": "DEF",
},
{
"id": 3,
"name": "GHJ",
}
]
},
{
"id": 2,
"name": "IT",
"merchant": [
{
"id": 1,
"name": "Apple",
},
{
"id": 2,
"name": "HP",
},
{
"id": 3,
"name": "Google",
}
]
}
]
}
I thought of using multiple $.each but it have to iterate few times and it's quite redundant.
I would prefer using Javascript for loop, that way you can skip iterating over every object once required element is found.
Without jQuery (using for)
var i, j, merchant = null;
for(i = 0; i < data['industries'].length; i++){
if(data['industries'][i]['id'] == arg[0]['industry_Id']){
for(j = 0; j < data['industries'][i]['merchant'].length; j++){
if(data['industries'][i]['merchant'][j]['id'] == arg[0]['merchant_id']){
merchant = data['industries'][i]['merchant'][j];
break;
}
}
if(merchant !== null){ break; }
}
}
With jQuery (using $.each)
var merchant_found = null;
$.each(data['industries'], function(i, industry){
if(industry['id'] == arg[0]['industry_Id']){
$.each(industry['merchant'], function(i, merchant){
if(merchant['id'] == arg[0]['merchant_id']){
merchant_found = merchant;
}
return (!merchant_found);
});
}
return (!merchant_found);
});
var arg = [{"industry_Id":1,"merchant_id":2}];
var data = {
"industries": [
{
"id": 1,
"name": "oil and gas",
"merchant": [
{
"id": 1,
"name": "ABC",
},
{
"id": 2,
"name": "DEF",
},
{
"id": 3,
"name": "GHJ",
}
]
},
{
"id": 2,
"name": "IT",
"merchant": [
{
"id": 1,
"name": "Apple",
},
{
"id": 2,
"name": "HP",
},
{
"id": 3,
"name": "Google",
}
]
}
]
};
var i, j, merchant = null;
for(i = 0; i < data['industries'].length; i++){
if(data['industries'][i]['id'] == arg[0]['industry_Id']){
for(j = 0; j < data['industries'][i]['merchant'].length; j++){
if(data['industries'][i]['merchant'][j]['id'] == arg[0]['merchant_id']){
merchant = data['industries'][i]['merchant'][j];
break;
}
}
if(merchant !== null){ break; }
}
}
console.log(merchant);
document.writeln("<b>Without jQuery:</b><br>");
document.writeln((merchant !== null) ? "Found " + merchant['name'] : "Not found");
var merchant_found = null;
$.each(data['industries'], function(i, industry){
if(industry['id'] == arg[0]['industry_Id']){
$.each(industry['merchant'], function(i, merchant){
if(merchant['id'] == arg[0]['merchant_id']){
merchant_found = merchant;
}
return (!merchant_found);
});
}
return (!merchant_found);
});
console.log(merchant_found);
document.writeln("<br><br><b>With jQuery:</b><br>");
document.writeln((merchant_found) ? "Found " + merchant_found['name'] : "Not found");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
selectors.map(function(selector) {
return data.industries.filter(function(industry) {
return industry.id == selector.industry_Id;
})[0].merchant.filter(function(merchant) {
return merchant.id == selector.merchant_id;
})[0].name;
});
// => DEF
If you want "HP", you want industry 2, not industry 1.
.filter(...)[0] is not really optimal. You could use .find(...), but that is not yet universally supported. Or you could use plain old JavaScript and write for loops instead to make it fast. Or you could use objects with ID keys instead of arrays to make lookups faster.
When it comes into a position where collection of data is what you're processing, I suggest you to take a look at underscore.js. It's not optimal choice for the best performance but it does make you code more readable and makes more sense especially when compared with loop.
Say data is a variable which stores your JSON data.
Try this:
// Given this selector criteria
var select = [{"industry_Id":1,"merchant_id":2}];
function filterByCriteria(criteria, data){
var match = [];
_.each(criteria, function(crit){
function matchIndustry(rec){ return rec.id===crit.industry_Id }
function matchMerchant(rec){ return rec.id===crit.merchant_id }
// Filter by industry id
var industry = _.first(_.where(data.industry, matchIndustry));
// Filter by merchant id
var merchant = _.where(industry.merchant, matchMerchant);
_.each(merchant, function addToMatchResult(m){
match.push(m.name);
});
});
return match;
}
var filteredData = filterByCriteria(select, data);
From snippet above, any merchants which match the search criteria will be taken to the match list. Is it more readable to you?
Do you even need numerical id's? Gets super easy when you don't.
/*
{
"industry": {
"oil and gas":{
"merchant": {
"ABC": {
"name": "ABC oil"
},
"DEF": {
"name": "DEF gas"
},
"GHJ" :{
"name": "GHJ oil and gas"
}
}
},
"IT": {
"merchant": {
"Apple" : {
"name": "Apple computers"
},
"HP": {
"name": "Hewlett Packard"
},
"Google": {
"name": "Google. Maw haw haw"
}
}
}
}
}
*/
var data = '{"industry": {"oil and gas":{"merchant": {"ABC": {"name": "ABC oil"},"DEF": {"name": "DEF gas"},"GHJ" :{"name": "GHJ oil and gas"}}},"IT": {"merchant": {"Apple" : {"name": "Apple computers"},"HP": {"name": "Hewlett Packard"},"Google": {"name": "Google. Maw haw haw"}}}}}';
data = JSON.parse(data);
var merchant = data.industry['IT'].merchant['HP'];
alert(merchant.name);
//console.log(merchant.name);

Search deep nested

I am working on a solution where I need to search for an element in a deeply nested JSON by its id. I have been advised to use underscore.js which I am pretty new to.
After reading the documentation http://underscorejs.org/#find , I tried to implement the solution using find, filter and findWhere.
Here is what I tried using find :
var test = {
"menuInputRequestId": 1,
"catalog":[
{
"uid": 1,
"name": "Pizza",
"desc": "Italian cuisine",
"products": [
{
"uid": 3,
"name": "Devilled chicken",
"desc": "chicken pizza",
"prices":[
{
"uid": 7,
"name": "regular",
"price": "$10"
},
{
"uid": 8,
"name": "large",
"price": "$12"
}
]
}
]
},
{
"uid": 2,
"name": "Pasta",
"desc": "Italian cuisine pasta",
"products": [
{
"uid": 4,
"name": "Lasagne",
"desc": "chicken lasage",
"prices":[
{
"uid": 9,
"name": "small",
"price": "$10"
},
{
"uid": 10,
"name": "large",
"price": "$15"
}
]
},
{
"uid": 5,
"name": "Pasta",
"desc": "chicken pasta",
"prices":[
{
"uid": 11,
"name": "small",
"price": "$8"
},
{
"uid": 12,
"name": "large",
"price": "$12"
}
]
}
]
}
]
};
var x = _.find(test, function (item) {
return item.catalog && item.catalog.uid == 1;
});
And a Fiddle http://jsfiddle.net/8hmz0760/
The issue I faced is that these functions check the top level of the structure and not the nested properties thus returning undefined. I tried to use item.catalog && item.catalog.uid == 1; logic as suggested in a similar question Underscore.js - filtering in a nested Json but failed.
How can I find an item by value by searching the whole deeply nested structure?
EDIT:
The following code is the latest i tried. The issue in that is that it directly traverses to prices nested object and tries to find the value. But my requirement is to search for the value in all the layers of the JSON.
var x = _.filter(test, function(evt) {
return _.any(evt.items, function(itm){
return _.any(itm.outcomes, function(prc) {
return prc.uid === 1 ;
});
});
});
Here's a solution which creates an object where the keys are the uids:
var catalogues = test.catalog;
var products = _.flatten(_.pluck(catalogues, 'products'));
var prices = _.flatten(_.pluck(products, 'prices'));
var ids = _.reduce(catalogues.concat(products,prices), function(memo, value){
memo[value.uid] = value;
return memo;
}, {});
var itemWithUid2 = ids[2]
var itemWithUid12 = ids[12]
I dont use underscore.js but you can use this instead
function isArray(what) {
return Object.prototype.toString.call(what) === '[object Array]';
}
function find(json,key,value){
var result = [];
for (var property in json)
{
//console.log(property);
if (json.hasOwnProperty(property)) {
if( property == key && json[property] == value)
{
result.push(json);
}
if( isArray(json[property]))
{
for(var child in json[property])
{
//console.log(json[property][child]);
var res = find(json[property][child],key,value);
if(res.length >= 1 ){
result.push(res);}
}
}
}
}
return result;
}
console.log(find(test,"uid",4));

How to print matched and not matched based on matched condtion using angular?

{
"_id": {
"$oid": "5705f793e4b0acd6e2456804a"
},
"Categories": [
{
"mainmodels": [
{
"submodels": [
{
"price": "2000",
"submodelname": "lumia021",
"Remainingphones": "2",
"Bookedphones": "8",
"Numofphones": "10"
},
{
"price": "4000",
"submodelname": "lumia K6",
"Remainingphones": "0",
"Bookedphones": "15",
"Numofphones": "15"
}
],
"Status": "Active",
"modelname": "lumia",
"fromdate": "2016-04-01T16:39:12.051Z",
"todate": "2016-04-31T19:19:44.051Z"
}
],
"brand": "nokia"
}
],
"rank": "1",
"name": "kalasipalaya"
}
I have given my object above i need to check every submodel(here two sumodels is there)Numofphones and Bookedphones are matched . if both(here i given two submodel) Numofphones and Bookedphones are matched i need to print matched otherwise i need to print not matched how can i solve this one help me out .
//This will take to submodel array of object
var _getSubModel = m[0].Categories[0].mainmodels[0].submodels;
var _newArray2 = [];
//Checking if Bookedphones of first object submodel, is same with other objects.
var _newArray = _getSubModel.filter(function(item){
return item.Bookedphones == _getSubModel[0].Bookedphones;
})
// If all the Bookedphones are same then length of _newArray & submodel will be same.
// If same then check for Numofphones
if(_getSubModel.length == _newArray.length){
_newArray2 = _getSubModel.filter(function(item){
return item.Numofphones == _getSubModel[0].Numofphones;
})
// If all Numofphones are same,then length of _newArray2 & submodel will be same
if(_getSubModel.length == _newArray2.length){
console.log('Matched');
}
else{
console.log('Not Matched');
}
}
else{
console.log('Not Matched');
}
Check this jsfiddle
You can use custom filter something like that:
var result = [];
angular.forEach(submodels, function (submodel) {
if(submodel.Numofphones == submodel.Bookedphones)
result.push(submodel);
});
return result;
http://jsfiddle.net/y7r1xe0t/236/
UPDATED: http://jsfiddle.net/y7r1xe0t/237/
return function (submodels, matched_or_not) {
var result = [];
angular.forEach(submodels, function (submodel) {
if(matched_or_not && submodel.Numofphones == submodel.Bookedphones)
result.push(submodel);
else if(!matched_or_not && submodel.Numofphones != submodel.Bookedphones)
result.push(submodel);
});
return result;
};
Filter will return matched object when you send true.

Categories

Resources