How would I define duplicate keys in a json array? [duplicate] - javascript

This question already has answers here:
How can I access and process nested objects, arrays, or JSON?
(31 answers)
Closed 4 years ago.
I am making a program that parses json files for dnd information. I have completed the program, however, I cannot figure out how to define the duplicate keys for the various attacks without manually giving thousands of keys unique ids.
Part of my JSON file:
{
"special_abilities": [
{
"name": "Legendary Resistance (3/Day)",
"desc": "If the tarrasque fails a saving throw, it can choose to succeed instead.",
"attack_bonus": 0
},
{
"name": "Magic Resistance",
"desc": "The tarrasque has advantage on saving throws against spells and other magical effects.",
"attack_bonus": 0
},
{
"name": "Reflective Carapace",
"desc": "Any time the tarrasque is targeted by a magic missile spell, a line spell, or a spell that requires a ranged attack roll, roll a d6. On a 1 to 5, the tarrasque is unaffected. On a 6, the tarrasque is unaffected, and the effect is reflected back at the caster as though it originated from the tarrasque, turning the caster into the target.",
"attack_bonus": 0
},
{
"name": "Siege Monster",
"desc": "The tarrasque deals double damage to objects and structures.",
"attack_bonus": 0
}
]
}
So, how would I define each of the name keys?
If I can define what I posted up there as searchFile.special_abilities, how would I define searchFile.special_abilities.name?

Your JSON is valid. You would access the parsed JSON data like so:
const searchFile = JSON.parse(jsonVarName)
const index = 2 // or whatever index you want
const name = searchFile.special_abilities[index].name
You can also use the various array methods to do all sorts of interesting things with the data, like searching by name:
const siegeMonster = searchFile.special_abilities.find(ability => ability.name === 'Siege Monster')

I'd suggest using a object of arrays instead, indexed by name, that way the name is never duplicated, and there's no need for separate unique identifiers. For example:
"special_abilities": {
"Some Name": [
{
"desc": "Description 1",
"attack_bonus": 0
},
{
"desc": "Description 2",
"attack_bonus": 5
}
],
"Some Other Name": [
{
"desc": "Some Other Description",
"attack_bonus": 2
}
]
}
Then, you could access special_abilities['Some name'] to get to the array, and iterate over the array to find what you're looking for. (Use Object.entries to get both the key and the value at once, eg Object.entries(special_abilities).forEach(([name, arr]) => { ... )

Related

how can I retrieve specific property of an object of multiple objects [duplicate]

This question already has answers here:
Perform .join on value in array of objects
(14 answers)
Closed 1 year ago.
I need help in getting values of specific property of an array of multiple objects
I have an array like this:
[
{
"id": 1,
"name": "skill 1"
},
{
"id": 2,
"name": "skill 2"
},
{
"id": 3,
"name": "skill 3"
}]
and I want to get a string like this :
skill 1 - skill 2 - skill 3
First step is to extract name. You can use map.
elements.map(x=>x.name)
Second step is to join it to one string using join
const result = elements.map(x=>x.name).join(' - ');

Retrieve object with a key in javascript

I have following object, and if I want to retrieve only soccer, then I put soccer as follows,
sports['soccer'] does not bring it.
I wonder what I am missing here?
sports = [] ;
sports = [{
"soccer": {
"type": "foot",
"player": 11
},
"basketball": {
"type": "hand",
"player": 5
}
}]
Your current code creates an array with a single object. One solution is to just create an object instead:
sports = {
"soccer": {
"type": "foot",
"player": 11
},
"basketball": {
"type": "hand",
"player": 5
}
}
Now you can use sports.soccer or sports['soccer'] to access the soccer data.
If you really want an array of objects, you first need to subscript the array to get the first object:
sports[0].soccer
or
sports[0]['soccer']
var sports is an array with objects inside.
If you set it up like this:
sports = [] ;
sports = {
"soccer": {
"type": "foot",
"player": 11
},
"basketball": {
"type": "hand",
"player": 5
}
}
then you will be able to call sports['soccer'] or even sports.soccer.
Alternately, if you need it to remain an array, then you'll need to do more work.
Something like this should do the trick.
for(i=0; i < sports.length; i++) {
if("soccer" in sports[i]){
console.log(sports[i].soccer.type);
console.log(sports[i].soccer.player);
}
}
The console.logs represent whatever you want to do with the values
I think you really need to reiterate the basics of javascript a bit.
In JS we can create data structures on the fly with literal syntax. For example:
let normalArr = new Array();
let literalArr = [];
let normalObj = new Object();
let literalObj = {};
When you create arrays and objects with literal syntax you can initialize arrays with elements and object with properties on the fly. This is what exactly happened in your example:
sports = [{
"soccer": {
"type": "foot",
"player": 11
},
"basketball": {
"type": "hand",
"player": 5
}
}];
The code can be broken down in the following way:
You created an array which was stored in the sports variable using the array literal syntax (created an array on the fly).
You created 1 element of the array with the object literal syntax (creating an object on the fly)
This object (located inside the array) has 2 properties, soccer and basketball which are also object created with object literal syntax.
To access one of there objects you need to do the following:
const sports = [{
"soccer": {
"type": "foot",
"player": 11
},
"basketball": {
"type": "hand",
"player": 5
}
}];
// accessing the first element of the sports array
console.log(sports[0].soccer);
console.log(sports[0].basketball);
As others have pointed out, you have an array of objects, not a single object. You can use the find() method to find the element that has the soccer property, and then access that property.
var soccer = sports.find(s => 'soccer' in s)['soccer'];

Retrieve value from object having key and index as a string: 'array[0].key' [duplicate]

This question already has answers here:
Access a nested property with a string [duplicate]
(5 answers)
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Closed 4 years ago.
I'm working with some specific library for forms in javascript. In this library if I have:
{
"id": 1,
"order": 0,
"title": "A title",
},
I can do:
const field = 'order';
form.getState().values[field]
And I'll get the title value.
Now let's say that I have this data:
{
"id": 1,
"order": 0,
"title": "A title",
"Tags": [
{
"id": 1,
"name": "Tag one",
},
{
"id": 2,
"name": "Tag two",
}
]
},
And also I have access to a string with the name of the field for tags, the index of the array, and the field I want to retrieve. But I have all this in a string:
Tags[0].name
If I do:
const field = 'Tags[0].name';
form.getState().values[field]
It will return undefined, because will try to find the key Tags[0].name in the object. So: how can I do to retrieve the name property from a specific index in the Tags array, having Tags[0].name as a string?
A bit nasty but quick and working way to do it is to use eval:
const field = 'Tags[0].name';
let stateValues = form.getState().values;
let tagName = eval(`stateValues.${ field }`)
Other approach might be to split and parse the field path using regexp and then traverse the object property by property.

Indexing array values in an object in an IndexedDB

For a Chrome app, wich stores data in IndexedDB, i have a object like this:
var simplifiedOrderObject = {
"ordernumber": "123-12345-234",
"name": "Mr. Sample",
"address": "Foostreet 12, 12345 Bar York",
"orderitems": [
{
"item": "brush",
"price": "2.00"
},
{
"item": "phone",
"price": "30.90"
}
],
"parcels": [
{
"service": "DHL",
"track": "12345"
},
{
"service": "UPS",
"track": "3254231514"
}
]
}
If i store the hole object in an objectStore, can i use an index for "track", which can be contained multiple times in each order object?
Or is it needed or possibly better/faster to split each object into multiple objectStores like know from relational DBs:
order
orderitem
parcel
The solution should also work in a fast way with 100.000 or more objects stored.
Answering my own question: I have made some tests now. It looks like it is not possible to do this with that object in only 1 objectStore.
An other example object which would work:
var myObject = {
"ordernumber": "123-12345-234",
"name": "Mr. Sample",
"shipping": {"method": "letter",
"company": "Deutsche Post AG" }
}
Creating an index will be done by:
objectStore.createIndex(objectIndexName, objectKeypath, optionalObjectParameters);
With setting objectKeypath it is possible to address a value in the main object like "name":
objectStore.createIndex("name", "name", {unique: false});
It would also be possible to address a value form a subobject of an object like "shipping.method":
objectStore.createIndex("shipping", "shipping.method", {unique: false});
BUT it is not possible to address values like the ones of "track", which are contained in objects, stored in an array. Even something like "parcels[0].track" to get the first value as index does not work.
Anyhow, it would be possible to index all simple elements of an array (but not objects).
So the following more simple structure would allow to create an index entry for each parcelnumber in the array "trackingNumbers":
var simplifiedOrderObject = {
"ordernumber": "123-12345-234",
"name": "Mr. Sample",
"address": "Foostreet 12, 12345 Bar York",
"orderitems": [
{
"item": "brush",
"price": "2.00"
},
{
"item": "phone",
"price": "30.90"
}
],
"trackingNumbers": ["12345", "3254231514"]
}
when creating the index with multiEntry set to true:
objectStore.createIndex("tracking", "trackingNumbers", {unique: false, multiEntry: true});
Anyhow, the missing of the possibility to index object values in arrays, makes using indexedDB really unneeded complicated. It's a failure in design. This forces the developer to do things like in relational DBs, while lacking all the possibilities of SQL. Really bad :(

Keep order of objects inside a JSON String after they are parsed

I receive the following JSON string from an API function.
"Inbound": {
"callRelatedFields": ["ANI",
"DNIS"],
"objects": {
"Contact": [{
"displayName": "Name",
"apiName": "Name"
},
{
"displayName": "Email",
"apiName": "Email"
}],
"Account": [{
"displayName": "Account Name",
"apiName": "Name"
},
{
"displayName": "Phone",
"apiName": "Phone"
},
{
"displayName": "Fax",
"apiName": "Fax"
}],
"cnx__Phone__c": [{
"displayName": "Phone Name",
"apiName": "Name"
},
{
"displayName": "Phone Number Line 1",
"apiName": "cnx__Phone_Number_Line_1__c"
},
{
"displayName": "Phone Number Line 2",
"apiName": "cnx__Phone_Number_Line_2__c"
},
{
"displayName": "Type",
"apiName": "cnx__Type__c"
},
{
"displayName": "Location",
"apiName": "cnx__Location__c"
},
{
"displayName": "Call Manager",
"apiName": "cnx__Call_Manager__c"
},
{
"displayName": "Mac Address",
"apiName": "cnx__Mac_Address__c"
}]
},
"screenPopSettings": {
"screenPopsOpenWithin": "ExistingWindow",
"SingleMatch": {
"screenPopType": "PopToEntity"
},
"NoMatch": {
"screenPopType": "DoNotPop"
},
"MultipleMatches": {
"screenPopType": "DoNotPop"
}
}
}
The order of the objects inside "objects" is important!
But when i parse this JSON string with JSON.parse, the order of those objects is lost.
Is there any good way to keep the order of those objects after they are parsed.
I tried to manipulate the string and convert the whole "objects" into an array, but this turned out to become way too complicated and hacky.
I have a suspicion that the thing that makes you think the keys have changed order is that Chrome devtools show objects with their keys sorted in alphabetical order. Whereas if you use Object.keys() or the equivalent JS to manually iterate through the keys, you will find they come out in the order they were defined in the JSON string.
Here is the equivalent JS for Object.keys():
function objectKeys(obj) {
var keys = [];
if (!obj) return keys;
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
keys.push(key);
}
}
}
When I call this with the objects part of the parsed object I get the following array:
["Contact", "Account", "cnx__Phone__c"]
Unfortunately object properties are unordered in JavaScript so you shouldn't rely on being able to iterate over them in a particular sequence.
I would suggest accessing the properties by name in the order you need them, rather than just iterating over the list.
As per the JSON standard, an object is unordered. So if you care about the order "Contact", "Account", "cnx__Phone__c", put them in an array ([]).
Maybe it's enough to put the property names themselves in an array next to the .objects themselves, so that you still can access them by their names. Many structures are valid solutions.
This solution works only if the properties and the data does not contain one of these characters: {, } and :.
Maybe you replace the curly brackets to square brackets and ": to #",. After that, you can the JSON string parse and get all objects replaced by arrays. The reading is: first value is the property (marked with # at the end) and the second value is the value.
The replacement machanism shuld be improved, in particular the replacement of ":, which can sometimes be wrong, and the search of the curly brackets.
var json = '{"Inbound":{"callRelatedFields":["ANI","DNIS"],"objects":{"Contact":[{"displayName":"Name","apiName":"Name"},{"displayName":"Email","apiName":"Email"}],"Account":[{"displayName":"Account Name","apiName":"Name"},{"displayName":"Phone","apiName":"Phone"},{"displayName":"Fax","apiName":"Fax"}],"cnx__Phone__c":[{"displayName":"Phone Name","apiName":"Name"},{"displayName":"Phone Number Line 1","apiName":"cnx__Phone_Number_Line_1__c"},{"displayName":"Phone Number Line 2","apiName":"cnx__Phone_Number_Line_2__c"},{"displayName":"Type","apiName":"cnx__Type__c"},{"displayName":"Location","apiName":"cnx__Location__c"},{"displayName":"Call Manager","apiName":"cnx__Call_Manager__c"},{"displayName":"Mac Address","apiName":"cnx__Mac_Address__c"}]},"screenPopSettings":{"screenPopsOpenWithin":"ExistingWindow","SingleMatch":{"screenPopType":"PopToEntity"},"NoMatch":{"screenPopType":"DoNotPop"},"MultipleMatches":{"screenPopType":"DoNotPop"}}}}';
json = json.replace(/{/g, '[').replace(/}/g, ']').replace(/"\:/g, '#",');
json = JSON.parse(json);
document.write('<pre>' + JSON.stringify(json, 0, 4) + '</pre>');
#GregL is right the JSON parsed came in alphabetic or in case of a number in ascending order and to keep the order you'll need an incremented number logic like:
var position_in_array = 0
var name = 'screenPopSettings'
object[`${position_in_array}${name}`] = value
position_in_array += 1
The parseJson returns data in object form and object doesn't has index. So we should define custom index of data array, if we want to keep the array index.
Example:
$arr[0] = array(
'Contact'=>array(
'key1'=>'val',
)
);
$arr[1] = array(
'Account'=>array(
'key1'=>'val',
)
);
It will produce the output as per the array index originally defined before parseJson function call.

Categories

Resources