Nested Json Access Value - javascript

Here is my Json-String:
{
"batchcomplete":"",
"query":{
"pages":{
"104352":{
"pageid":104352,
"ns":0,
"title":"student"
}
}
}
}
I want to access tha first number, in this example "103452", not the on after pageid, although they always should be the same.
I tried the following until know, but don´t get why it wont work.
JSONName.query.pages;
it always returns me Object object.

Assuming you have a JavaScript object you can get the keys of an object which would contain your string.
const obj = {
"batchcomplete": "",
"query": {
"pages": {
"104352": {
"pageid": 104352,
"ns": 0,
"title": "student"
}
}
}
}
// Get the keys for pages
const keys = Object.keys(obj.query.pages);
// Print out the first key
console.log(keys[0]);

Might be easier to find it during the parsing:
var n, j = '{"batchcomplete":"","query":{"pages":{"104352":{"pageid":104352,"ns":0,"title":"student"}}}}';
var result = JSON.parse(j, (key, value) => (n = n || +key, value));
console.log( n ); console.log( result );

Related

Compare key values within object for duplicate

I have an object:
myObj = {
attendent-0-id:"123",
attendent-0-name:"Bob Smith",
attendent-1-id:"1234",
attendent-1-name:"Alex Smith",
attendent-2-id:"123",
attendent-2-name:"Charlie Smith",
attendent-maxGuest:1,
attendent-party-name:"",
}
I need to create a loop that go through myObj and find all the id's and then compares them for duplicates. So in this case it would log an error because attendent-0-id is equal to attendent-2-id.
If I do find duplicates I need to set a flag to true;
I have tried a bunch of things and am just stuck at this point. Thanks for any help.
In your case you can go through myObj using Object.keys() via:
for (const key of Object.keys(obj))
use a plain object as a map to store the previous values of the ids:
const map = {};
use a regex pattern to make sure only the specific ids are evaluated:
const pattern = /^attendent-\d+-id$/;
and then with the help of the map, log the error on duplicate ids:
if (value in map) {
console.error(`${map[value]} is equal to ${key}, which is ${value}`);
}
Example:
const myObj = {
'attendent-0-id': "123",
'attendent-0-name': "Bob Smith",
'attendent-1-id': "1234",
'attendent-1-name': "Alex Smith",
'attendent-2-id': "123",
'attendent-2-name': "Charlie Smith",
'attendent-maxGuest': 1,
'attendent-party-name': "",
};
function errorOnDuplicateIds(obj) {
const map = {};
const pattern = /^attendent-\d+-id$/;
for (const key of Object.keys(obj)) {
if (pattern.test(key)) {
const value = obj[key]
if (value in map) {
console.error(`${map[value]} is equal to ${key}, which is ${value}`);
} else {
map[value] = key
}
}
}
}
errorOnDuplicateIds(myObj);
const ids = []; // keep track of found ids
Object.keys(myObj).forEach(key => { // iterate over all properties of myObj
// check if property name is in format "attendent-" *some number* "-id"
if (/^attendent-\d+-id$/.test(key)) {
// check if the id has already been found
if (ids.findIndex(id => id === myObj[key]) !== -1) {
console.log('error');
} else {
ids.push(myObj[key]);
}
}
});
You can use Object.entries and a Map (keyed by value) for this:
var myObj = {"attendent-0-id":"123","attendent-0-name":"Bob Smith","attendent-1-id":"1234","attendent-1-name":"Alex Smith","attendent-2-id":"123","attendent-2-name":"Charlie Smith","attendent-maxGuest":1, "attendent-party-name":""};
var dupes = [...Object.entries(myObj).reduce(
(map, [key,val]) => map.set(val, (map.get(val) || []).concat(key)),
new Map
).values()].filter(keys => keys.length > 1);
console.log(dupes);
This solution does not give any particular meaning to the format of the keys.
Having said that, your object structure looks suspicious of bad design: you should not have enumerations in your object keys. For that you should use arrays.
Object.values(myObj) will create an array of all values and then you can use any way to find duplicate elements in that array.
var myValues = Object.values(myObj); //This will create an array of all values
var uniq = myValues.map((val) => {
return {count: 1, val: val}
}).reduce((a, b) => {
a[b.val] = (a[b.val] || 0) + b.count
return a
}, {});
var duplicates = Object.keys(uniq).filter((a) => uniq[a] > 1)
if (duplicates.length) {
return true;
} else {
return false;
}
My first advice would be to redefine your object to something more flexible.
let myObject = {
attendants : [
{
id: "123",
name: "Bob Smith"
},
{
id: "456",
name: "Alex Smith"
},
{
id: "768",
name: "Charlie Smith"
},
],
maxGuest: 1,
partyName: ""
};
This will allow you to iterate the attendants.
for (var attendant in myObject.attendants){
doSomething(attendant.id, attendant.name);
}
You can also sort the attendant:
// Sort by id
myObject.attendants.sort(function(left, right){
return left.value - right.value;
});
// Sort by name
myObject.attendants.sort(function (left, right){
var leftName = left.name.toLowerCase();
var rightName = right.name.toLowerCase();
if (leftName < rightName) return -1;
if (leftName > rightName) return 1;
return 0;
});
Now, lets assume you don't have a choice. Then it gets complicated.
You need to create (or modify an existent) a sort algorithm so it can use keys that are generated as:
myObject[`attendent-${index}-id`]
myObject[`attendent-${index}-name`]
and keep the pair

JS: Finding next key in json

I have the following json:
{0: "2", 1: "2", $$hashKey: "object:35", undefined: "1"}
Currently I am trying to get its key-value with the below code:
var data = JSON.stringify(row);
var result = $.parseJSON(data);
$.each(result, function (k, v) {
//display the key and value pair
console.log(k, v);
});
The above code works fine and I can get my key-value from it.
Now what I am trying to get is the next key-value pairs within the $.each loop.
For example if in the loop the current key is "0" I want to get the next key "1" in the same call itself. If in the loop the current key is "1" I want to get the next key "$$hashKey" along with their values.
Is it possible to do so? I am open to code changes above if required.
You can use Object.keys to get the keys to an array, then run through it with a forEach to have access to the keys index. Important to note that objects are unordered, so your key order one time may differ from the next time:
var keys = Object.keys(obj);
keys.forEach(function(key, index) {
var nextIndex = index + 1;
if (nextIndex === keys.length) return; //out of bounds
var nextKey = keys[nextIndex];
});
Edit: As pointed out by the comments - if you want the keys in the same order each time, call .sort() on your keys array with your desired sort logic.
Understanding now that the goal is to retrieve keys in the order they appear in JSON, a couple of thoughts:
(1) if you control the source of the object ("row" in the OP code), don't represent it as an object. instead use an array of key-value pairs: [[0, "2"], [1, "2"], [$$hashKey, "object:35"], [undefined, "1"]].
otherwise, (2) roll your own JSON parser that returns an array of key-value pairs for an object. This post looks to be a sensible start. Or, you can vastly simplify the task if you are able to make certain assumptions about the values, for example, say you know that all values are strings...
// parse a string representing an object, returning an array of key-value pairs.
// assumes values are strings that do not contain commas or colons
function myProbablyNegligentlySimpleJSONParse(string) {
let trimmed = string.trim().slice(1, -1);
let components = trimmed.split(',');
return components.map(kvString => {
let kv = kvString.split(':');
return [ kv[0].trim(), kv[1].trim() ];
});
}
forEach passes the current index to the iterator function, so that int can be used to look ahead or behind in the iteration.
var data = '{0: "2", 1: "2", $$hashKey: "object:35", undefined: "1"}';
let result = myProbablyNegligentlySimpleJSONParse(data);
result.forEach(function (pair, index) {
let [k, v] = pair; // now k and v are your key and value
console.log(`key is ${k} value is ${v}`)
if (index < result.length-1) {
let [nextK, nextV] = result[index+1];
console.log(`next key is ${nextK} next value is ${nextV}`);
}
});
You could turn your object into an iterable and which will return the next [key, value] pair each time you call next on the iterator:
function makeIterable(o) {
o[Symbol.iterator] = () => {
var keys = Object.keys(o);
var i = 0;
return {
next() {
var done = false;
var value = [keys[i + 1], o[keys[i + 1]]];
if (i >= (keys.length - 1)) {
done = true;
}
i++;
return {
value,
done
}
}
};
}
}
var jsonStr = '{ "0": "2", "1": "2", "$$hashKey": "object:35", "undefined": "1" }';
var obj = JSON.parse(jsonStr);
makeIterable(obj);
var itr = obj[Symbol.iterator]();
while (true) {
var item = itr.next();
if (item.done) {
break;
}
console.log(item.value);
}

Javascript, how to split key with dot to recovery json structure

I have a json, it is
{
"prop1.sub1.sub2": "content1",
"prop1.sub1.sub3": "content2",
"prop2.sub1.sub2": "content3",
"prop3.sub1.sub2": "content4"
}
I want to recovery the structure, like
{
"prop1": {
"sub1": {
"sub2" : "content1",
"sub3" : "content2"
}
},
"prop2": {
"sub1": {
"sub2" : "content3"
}
},
"prop3": {
"sub1": {
"sub2" : "content4"
}
}
}
I split the key with dot to get each key.
for (var key in json) {
var keySplit = key.split('.');
// Todo: recovery the structure
}
But not found a good solution.
Is anyone has solution?
You can use Array#reduce method.
var obj = {
"prop1.sub1.sub2": "content1",
"prop1.sub1.sub3": "content2",
"prop2.sub1.sub2": "content3",
"prop3.sub1.sub2": "content4"
};
// iterate over the property names
Object.keys(obj).forEach(function(k) {
// slip the property value based on `.`
var prop = k.split('.');
// get the last value fom array
var last = prop.pop();
// iterate over the remaining array value
// and define the object if not already defined
prop.reduce(function(o, key) {
// define the object if not defined and return
return o[key] = o[key] || {};
// set initial value as object
// and set the property value
}, obj)[last] = obj[k];
// delete the original property from object
delete obj[k];
});
console.log(obj);
Answer by Pranav C Balan is right for the question you asked. But JSON's might not be as simple as you have mentioned above and can have array's also and few keys might not have "." in them. To handle all these cases you can use the following one.
var obj = {
"prop1.sub1.sub2": "content1",
"prop1.sub1.sub3": "content2",
"prop2.sub1.sub2": "content3",
"prop3.0.sub2": "content4"
};
function createJSONStructure(obj) {
Object.keys(obj).forEach(function(k) {
var prop = k.split('.'); //split on . to get elements
if(prop.length >1){ //If there is no dot just key the value as is.
let data = obj;//Copy the default object to data in each loop
for(i=0;i<prop.length-1;i++){
if(data[prop[i]]){ // Check if the key exists
if((prop[i+1].match(/^\d+$/) && !Array.isArray(data[prop[i]])) // Check if the next key is a digit and the object we have is a JSON
|| (!prop[i+1].match(/^\d+$/) && Array.isArray(data[prop[i]]))){ // Check if the next key is not a digit and the object we have is a Array
throw new Error("Invalid header data"); //If any of the above cases satisfy we cannot add the key so we can throw an error.
}
data = data[prop[i]]; // If key exisits make the data variable as the value of the key
}else {
if(prop[i+1].match(/^\d+$/)){ //If the key is not available see if the next parameter is a digit or string to decide if its array or string
data[prop[i]] = [];
}else{
data[prop[i]] = {};
}
data = data[prop[i]]; //Assign this new object to data
}
};
data[prop[i]] = obj[k]; //Finally add the value to final key
delete obj[k]; // delete the exisiting key value
}
});
return obj;
}
console.log(createJSONStructure(obj));

Search and find numbers starting with particular number

I was trying to create a search plugin for my custom table plugin.
In my search I use
function getObjects(obj, key, val, path) {
for (var prop in obj) {
if (prop == key && obj[key].toLowerCase().match(val)) {
result.push(passName);
matchFlag = 1;
}
}
}
where
obj -> JSON
key -> search filter
val -> search keyword will be like '^m'
This works as long as the search keyword is a string/character.
How to handle scenario where search keyword is numeric? I tried using indexOf also.
Just make the value a String by concatenating an empty String:
function getObjects(obj, key, val, path) {
var value = val + "";
for (var prop in obj) {
if (prop == key && obj[key].toLowerCase().match(value)) {
result.push(passName);
matchFlag = 1;
}
}
}
The issue was from json, fixed it by adding toString()
function getObjects(obj, key, val, path) {
for (var prop in obj) {
if (prop == key && obj[key].toString().toLowerCase().match(val)) {
result.push(passName);
matchFlag = 1;
}
}
}
You can use this javascript library; DefiantJS (defiantjs.com) which extends the global object JSON with the method "search". Using this method, you can search a JSON structure with XPath expressions like this:
var data = [
{
"name": "Tom",
"age": 27
},
{
"name": "Lisa",
"age": 22
}
],
res1 = JSON.search( data, '//*[name = "Lisa"]' ),
res2 = JSON.search( data, '//*[age = 27]' ),
res3 = JSON.search( data, '//name[contains(.,"om")]/..' );
console.log( res1[0].age );
// 22
console.log( res2[0].name );
// Tom
console.log( res3[0] );
// { "name": "Tom", "age": 27 }
Here is a working fiddle:
http://jsfiddle.net/hbi99/2C8Ac/

Accessing elements of JSON object without knowing the key names

Here's my json:
{"d":{"key1":"value1",
"key2":"value2"}}
Is there any way of accessing the keys and values (in javascript) in this array without knowing what the keys are?
The reason my json is structured like this is that the webmethod that I'm calling via jquery is returning a dictionary. If it's impossible to work with the above, what do I need to change about the way I'm returning the data?
Here's an outline of my webmethod:
<WebMethod()> _
Public Function Foo(ByVal Input As String) As Dictionary(Of String, String)
Dim Results As New Dictionary(Of String, String)
'code that does stuff
Results.Add(key,value)
Return Results
End Function
You can use the for..in construct to iterate through arbitrary properties of your object:
for (var key in obj.d) {
console.log("Key: " + key);
console.log("Value: " + obj.d[key]);
}
Is this what you're looking for?
var data;
for (var key in data) {
var value = data[key];
alert(key + ", " + value);
}
{
"d":{
"key1":"value1",
"key2":"value2"
}
}
To access first key write:
let firstKey=Object.keys(d)[0];
To access value of first key write:
let firstValue= d[firstKey];
By using word "b", You are still using key name.
var info = {
"fname": "Bhaumik",
"lname": "Mehta",
"Age": "34",
"favcolor": {"color1":"Gray", "color2":"Black", "color3":"Blue"}
};
Look at the below snippet.
for(key in info) {
var infoJSON = info[key];
console.log(infoJSON);
}
Result would be,
Bhaumik
Mehta
Object {color1: "Gray", color2: "Black", color3: "Blue"}
Don’t want that last line to show up? Try following code:
for(key in info) {
var infoJSON = info[key];
if(typeof infoJSON !== "object"){
console.log(infoJSON);
}
}
This will eliminate Object {color1: “Gray”, color2: “Black”, color3: “Blue”} from showing up in the console.
Now we need to iterate through the variable infoJSON to get array value. Look at the following whole peace of code.
for(key in info) {
var infoJSON = info[key];
if (typeof infoJSON !== "object"){
console.log(infoJSON);
}
}
for(key1 in infoJSON) {
if (infoJSON.hasOwnProperty(key1)) {
if(infoJSON[key1] instanceof Array) {
for(var i=0;i<infoJSON[key1].length;i++) {
console.log(infoJSON[key1][i]);
}
} else {console.log(infoJSON[key1]);}
}
}
And now we got the result as
Bhaumik
Mehta
Gray
Black
Blue
If we use key name or id then it’s very easy to get the values from the JSON object but here we are getting our values without using key name or id.
Use for loop to achieve the same.
var dlist = { country: [ 'ENGLAND' ], name: [ 'CROSBY' ] }
for(var key in dlist){
var keyjson = dlist[key];
console.log(keyjson)
}

Categories