Skip to content

Instantly share code, notes, and snippets.

@hygull
Last active January 5, 2019 11:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hygull/be501e15886dd1ec7bf2333e853c1387 to your computer and use it in GitHub Desktop.
Save hygull/be501e15886dd1ec7bf2333e853c1387 to your computer and use it in GitHub Desktop.

https://stackoverflow.com/questions/54050750/prune-json-to-given-target-and-get-all-parent-keys/54051428#54051428

I found this problem very interesting and tried to solve (in a modular way) using recursion as follows.

Here only getParentKeys() will return you the expected result as you want.

Other functions are just helpers(callees) or independent.

Just go through the code starting from function testcase() which is starter.

Corrected one (Improved version of 2nd one)

	function getAllMatchedKeys(testData, searchWord) {
		let type = Object.prototype.toString.call(testData).slice(8, -1) // Array, Object, String, Number
		let arr = [];

		if(type == 'Object') { // If it is object
			let keys = Object.keys(testData);
			
			for(let key of keys) {
				if(key === searchWord) {
					arr.push(key);
					return arr;
				}

				if(Object.prototype.toString.call(testData[key]).slice(8, -1) === 'Object') {
					arr = getAllMatchedKeys(testData[key], searchWord);

					if(arr.length !== 0) {
						arr.push(key)
						return arr;
					}
				}
			}
		}

		return arr;
	}


	function getKeys(testData, searchWord) {
		let allKeys = getAllMatchedKeys(testData, searchWord);
		let parentKeys = allKeys.slice(1).reverse();
		
		let keys = {
			allKeys: allKeys,
			parentKeys: parentKeys
		};

		return keys;
	}


	function getParentKeys(testData, searchWord) {
		/*
			Returns the parent keys, excluing the search word
		*/

		let keys = getKeys(testData, searchWord);
		return keys["parentKeys"];
	}


	function testcase() {
		/*
			Test cases 
		*/

		let testData = {
			cars: {
				sedan: {
					toyota: 'value1',
					kia: 'value2',
					mercedes: 'value3'
				},
				compact: {
					bugatti: 'value1'
				},
				toyota: {
					car1: 'car-1',
					car2: 'car-2',
					car3: {
						redbull: 'favourite'
					}
				}
			},
			electronics: {
				computers: {
					mac: {
						macbook_pro: "value 1 1",
						macbook_air: "value 1 2"
					},
					pcs: 'value2'
				},
				mobiles: {
					apple: "value",
					samsung: "value"
				}
			}
		};

		// TEST CASE 1
		let macbookAllKeys = getKeys(testData, 'macbook_pro'); // Object
		/*
			{ allKeys: [ 'macbook_pro', 'mac', 'computers', 'electronics' ],
			  parentKeys: [ 'electronics', 'computers', 'mac' ] }
		*/

		// Pretty printing
		console.log(JSON.stringify(macbookAllKeys, null, 4));
		/*
			{
			    "allKeys": [
			        "macbook_pro",
			        "mac",
			        "computers",
			        "electronics"
			    ],
			    "parentKeys": [
			        "electronics",
			        "computers",
			        "mac"
			    ]
			}
		*/

		let macbookParentKeys = getParentKeys(testData, 'macbook_pro');
		console.log(macbookParentKeys); /* [ 'electronics', 'computers', 'mac' ] */

		// TEST CASE 2
		let kiaParentKeys = getParentKeys(testData, 'kia');
		console.log(kiaParentKeys); /* [ 'cars', 'sedan' ] */

		// TEST CASE 3 (I added extra keys to your testData for this)
		let redbullParentKeys = getParentKeys(testData, 'redbull');
		console.log(redbullParentKeys); /* [ 'cars', 'toyota', 'car3' ] */


		// TEST CASE 4 
		let sedanParentKeys = getParentKeys(testData, 'sedan');
		console.log(sedanParentKeys); /* [ 'cars' ] */
	}

	// Start
	testcase();

Does not work if key points to object and user is looking for that key (Above one is correct)

	function getAllMatchedKeys(testData, searchWord) {
		let type = Object.prototype.toString.call(testData).slice(8, -1) // Array, Object, String, Number
		let arr = [];

		if(type == 'Object') { // If it is object
			let keys = Object.keys(testData);
			
			for(let key of keys) {
				if(Object.prototype.toString.call(testData[key]).slice(8, -1) === 'Object') {
					arr = getAllMatchedKeys(testData[key], searchWord);

					if(arr.length !== 0) {
						arr.push(key)
						return arr;
					}
				} else {
					if(key === searchWord) {
						arr.push(key);
						return arr;
					}
				}
			}
		}

		return arr;
	}


	function getKeys(testData, searchWord) {
		let allKeys = getAllMatchedKeys(testData, searchWord);
		let parentKeys = allKeys.slice(1).reverse();
		
		let keys = {
			allKeys: allKeys,
			parentKeys: parentKeys
		};

		return keys;
	}


	function getParentKeys(testData, searchWord) {
		/*
			Returns the parent keys, excluing the search word
		*/

		let keys = getKeys(testData, searchWord);
		return keys["parentKeys"];
	}


	function testcase() {
		/*
			Test cases 
		*/

		let testData = {
			cars: {
				sedan: {
					toyota: 'value1',
					kia: 'value2',
					mercedes: 'value3'
				},
				compact: {
					bugatti: 'value1'
				},
				toyota: {
					car1: 'car-1',
					car2: 'car-2',
					car3: {
						redbull: 'favourite'
					}
				}
			},
			electronics: {
				computers: {
					mac: {
						macbook_pro: "value 1 1",
						macbook_air: "value 1 2"
					},
					pcs: 'value2'
				},
				mobiles: {
					apple: "value",
					samsung: "value"
				}
			}
		};

		// TEST CASE 1
		let macbookAllKeys = getKeys(testData, 'macbook_pro'); // Object
		/*
			{ allKeys: [ 'macbook_pro', 'mac', 'computers', 'electronics' ],
			  parentKeys: [ 'electronics', 'computers', 'mac' ] }
		*/

		// Pretty printing
		console.log(JSON.stringify(macbookAllKeys, null, 4));
		/*
			{
			    "allKeys": [
			        "macbook_pro",
			        "mac",
			        "computers",
			        "electronics"
			    ],
			    "parentKeys": [
			        "electronics",
			        "computers",
			        "mac"
			    ]
			}
		*/

		let macbookParentKeys = getParentKeys(testData, 'macbook_pro');
		console.log(macbookParentKeys); /* [ 'electronics', 'computers', 'mac' ] */

		// TEST CASE 2
		let kiaParentKeys = getParentKeys(testData, 'kia');
		console.log(kiaParentKeys); /* [ 'cars', 'sedan' ] */

		// TEST CASE 3 (I added extra keys to your testData for this)
		let redbullParentKeys = getParentKeys(testData, 'redbull');
		console.log(redbullParentKeys); /* [ 'cars', 'toyota', 'car3' ] */
	}

	// Start
	testcase();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment