How to delete nested json key dynamically? - javascript

This is the sample json:
{
"search": {
"facets": {
"author": [
],
"language": [
{
"value": "nep",
"count": 3
},
{
"value": "urd",
"count": 1
}
],
"source": [
{
"value": "West Bengal State Council of Vocational Education & Training",
"count": 175
}
],
"type": [
{
"value": "text",
"count": 175
}
],
}
}
There are several ways to delete key search.facets.source:
delete search.facets.source
delete jsobObj['search']['facets']['source']
var jsonKey = 'source';
JSON.parse(angular.toJson(jsonObj), function (key, value) {
if (key != jsonKey)
return value;
});
Above 1 & 2 are not dynamic, and 3 is one of the way but not a proper way. Because if source is present in another node then it will not work. Please anybody can tell me how to delete it dynamically in any kind of nested key. Because we can not generate sequence of array dynamically in above 2.

Assuming you're starting from this:
let path = 'search.facets.source';
Then the logic is simple: find the search.facets object, then delete obj['source'] on it.
Step one, divide the path into the initial path and trailing property name:
let keys = path.split('.');
let prop = keys.pop();
Find the facets object in your object:
let parent = keys.reduce((obj, key) => obj[key], jsonObj);
Delete the property:
delete parent[prop];

I have found out another solution, it is very easy.
var jsonKey = 'search.facets.source';
eval('delete jsonObj.' + jsonKey + ';');

Related

How can I pull a value from a JSON object from within another array?

My question title may not be the accurate way to describe this issue but it is the best I could come up with. I will make this very easy -- I am trying to get the value of VALUEIWANT from the below JSON object.
Any help would be greatly appreciated as I have been trying various methods on w3 schools for 2 hours now.
The closest I have gotten by hard coding was below:
const x =
{ "UserAttributes":
[ { "Name" : "sub"
, "Value": "54f5cdfb-6ec7-4683-fdasfasdf-2324234234"
}
, { "Name" : "custom:var"
, "Value": "VALUEIWANT"
}
, { "Name" : "email"
, "Value": "test.user#email.com"
}
]
, "Username": "testuser"
}
const y = x.UserAttributes[1].Value
// y here would result in VALUEIWANT
The problem with this is I am not sure that the variable will always be at index 1.
EDIT For Clarity My goal is to be able to retrieve this value of "VALUEIWANT" in my console. I need to be able to access the value by using the paired Name of "custom:var". I am unsure if this is possible.
The problem with this is I am not sure that the variable will always
be at index 1.
You need to find the index using findIndex (MDN)
const x = {
"UserAttributes": [{
"Name": "sub",
"Value": "54f5cdfb-6ec7-4683-fdasfasdf-2324234234"
}, {
"Name": "email",
"Value": "test.user#email.com"
}, {
"Name": "custom:var",
"Value": "VALUEIWANT"
}],
"Username": "testuser"
}
const index = x.UserAttributes.findIndex(item => item.Name === "custom:var");
const y = x.UserAttributes[index].Value;
console.log(y);
An helper function for this would be like below
const x = {
"UserAttributes": [{
"Name": "sub",
"Value": "54f5cdfb-6ec7-4683-fdasfasdf-2324234234"
}, {
"Name": "custom:var",
"Value": "VALUEIWANT"
}, {
"Name": "email",
"Value": "test.user#email.com"
}],
"Username": "testuser"
}
function getValue(x, name) {
const index = x.UserAttributes.findIndex(item => item.Name === name);
return index === -1 ? null : x.UserAttributes[index].Value;
}
// get email
console.log(getValue(x, 'email'));
// get custom:var
console.log(getValue(x, 'custom:var'))
Use Array.find on the x.UserAttributes array to search for the item with name of "custom:var", and take the value:
const valueYouWant = x.UserAttributes.find(ua => ua.Name === "custom:var").Value;

converting array to object while considering keys of the same value

I am trying to figure out an easy way to convert an array of objects to an object
I have an array of objects that looks like this:
[
{
"id": "-LP9_kAbqnsQwXq0oGDT",
"value": Object {
"date": 1541482236000,
"title": "First",
},
},
.... more objects here
]
And id like to convert it to an object with the timestamps as the keys, and arrays of objects corresponding to that date. If that key already exists, then add the object to the corresponding array associated with that key
{
1541482236000:
[{
"id": "-LP9_kAbqnsQwXq0oGDT",
"value": Object {
"date": 1541482236000,
"title": "First",
},
},
{
"id": "-LP9_kAbqnsQwXqZZZZ",
"value": Object {
"date": 1541482236000,
"title": "Some other title",
},
},
.... more objects here
],
1541482236001:
[{
"id": "-LP9_kAbqnsQ1234",
"value": Object {
"date": 1541482236001,
"title": "Another title",
},
},
.... more objects here
]
}
I was able to achieve something similar using reduce. However it does not handle adding objects to the array when their key already exists.
calendarReminders = action.value.reduce((obj, reminder) => {
dateKey = moment(reminder.value.date).format('YYYY-MM-DD')
obj[dateKey] = [reminder]
return obj;
}, {});
How can I do this?
You just need to check whether the object is already a key and if not add it with the value of an array. Then you can just push() into it:
let arr = [{"id": "-LP9_kAbqnsQwXq0oGDT","value": {"date": 1541482236000,"title": "First",},},{"id": "SomID","value": {"date": 1541482236000,"title": "Some other title",},},{"id": "A different ID","value": {"date": 1541482236001,"title": "A third title",},}]
let calendarReminders = arr.reduce((obj, reminder) => {
(obj[reminder.value.date] || (obj[reminder.value.date] = [])).push(reminder)
return obj;
}, {});
console.log(calendarReminders)
If you want to set the keys to a different format with moment, you should be able to do that without changing the basic idea.
Please test the below code!
First you iterate through your array of data,
if your result object/dictionary already has the key then you just add the current item
otherwise you make the key and set the value
const data = [];
let result = {};
for (const item of data) {
const key = item.value.date;
if (result.hasOwnProperty(key)) {
const prevData = result[key];
result[key] = [...prevData, item];
} else {
result[key] = [item];
}
}

Append one value from array of lists - react native

This API require me to send some data comma separated, when handling the user input I use checkboxes like so
<SelectMultiple
items={dairy}
selectedItems={this.state.selectedIngredients}
onSelectionsChange={this.onSelectionsChange} />
I can definitely see the inputs if I render selectedIngredients on a FlatList (using item.value) but when I try to print the actual url I am working with I got this [object,Object]
I used this.state.selectedIngredients in the view, here is the result:
url.com/api/?=[object Object],[object Object],[object Object]
Inside my search function I use that code to handle user inputs:
const { selectedIngredients } = this.state;
let url = "url.com/api/?i=" + selectedIngredients
In the documentation of the library they say the selected items is type array of string or { label, value } I used the method provided there to append the selected items:
onSelectionsChange = (selectedIngredients) => {
// selectedFruits is array of { label, value }
this.setState({ selectedIngredients})
}
I tried adding .value on both of them it didn't solve my problem. Could anyone one help please?
Console log this.state.selectedIngredients:
Array [
Object {
"label": "Goat cheese",
"value": "Goat cheese",
},
Object {
"label": "Cream cheese",
"value": "Cream cheese",
},
Object {
"label": "Butter",
"value": "Butter",
},
]
selectedIngredients = [
{
"label": "Goat cheese",
"value": "Goat cheese",
},
{
"label": "Cream cheese",
"value": "Cream cheese",
},
{
"label": "Butter",
"value": "Butter",
},
]
let selectedValues = selectedIngredients.map((ingredient)=> ingredient.value)
let selectedValuesInString = selectedValues.join(',');
console.log(selectedValuesInString)
It's a bit clumsy, but it'll give you a comma-separated string with no trailing comma.
const { selectedIngredients } = this.state;
let sep = "";
let selectedIngAsString = "";
selectedIngredients.forEach(s => {
selectedIngAsString += sep + s.value;
sep = ",";
});
let url = "url.com/api/?i=" + selectedIngAsString
See https://codesandbox.io/s/m5ynqw0jqp
Also, see Mohammed Ashfaq's for a much less clumsy answer.

Merge Arrays Combining Matching Objects in Angular Javascript

I have 2 array objects in Angular JS that I wish to merge (overlap/combine) the matching ones.
For example, the Array 1 is like this:
[
{"id":1,"name":"Adam"},
{"id":2,"name":"Smith"},
{"id":3,"name":"Eve"},
{"id":4,"name":"Gary"},
]
Array 2 is like this:
[
{"id":1,"name":"Adam", "checked":true},
{"id":3,"name":"Eve", "checked":true},
]
I want the resulting array after merging to become this:
[
{"id":1,"name":"Adam", "checked":true},
{"id":2,"name":"Smith"},
{"id":3,"name":"Eve", "checked":true},
{"id":4,"name":"Gary"},
]
Is that possible? I have tried angular's array_merge and array_extend like this:
angular.merge([], $scope.array1, $scope.array2);
angular.extend([], $scope.array1, $scope.array2);
But the above method overlap the first 2 objects in array and doesn't merge them based on matching data. Is having a foreach loop the only solution for this?
Can someone guide me here please?
Not sure if this find of merge is supported by AngularJS. I've made a snippet which does exactly the same:
function merge(array1, array2) {
var ids = [];
var merge_obj = [];
array1.map(function(ele) {
if (!(ids.indexOf(ele.id) > -1)) {
ids.push(ele.id);
merge_obj.push(ele);
}
});
array2.map(function(ele) {
var index = ids.indexOf(ele.id);
if (!( index > -1)) {
ids.push(ele.id);
merge_obj.push(ele);
}else{
merge_obj[index] = ele;
}
});
console.log(merge_obj);
}
var array1 = [{
"id": 1,
"name": "Adam"
}, {
"id": 2,
"name": "Smith"
}, {
"id": 3,
"name": "Eve"
}, {
"id": 4,
"name": "Gary"
}, ]
var array2 = [{
"id": 1,
"name": "Adam",
"checked": true
}, {
"id": 3,
"name": "Eve",
"checked": true
}, ];
merge(array1, array2);
Genuinely, extend in Angular works with object instead of array. But we can do small trick in your case. Here is another solution.
// a1, a2 is your arrays
// This is to convert array to object with key is id and value is the array item itself
var a1_ = a1.reduce(function(obj, value) {
obj[value.id] = value;
return obj;
}, {});
var a2_ = a2.reduce(function(obj, value) {
obj[value.id] = value;
return obj;
}, {});
// Then use extend with those two converted objects
var result = angular.extend([], a1_, a2_).splice(1)
Notes:
For compatibility, reduce may not work.
The after array will replace the previous one. This is because of implementation of extend in Angular.

Push Json filtered key values to nested ul with Javascript

I need help pushing the values from a filtered json, I need this generate a nested ul list, I can not modify the json format at this point, I you check the console.log you will see the values to create the list, at this point I can't figure how to complete the 'for loop' to render the html markup needed, any help will be appreciated, this is the jsfiddle http://jsfiddle.net/43jh9hzz/, and if you check the console log you will see the values.
This is the Js:
var json='';
var property_set = new Set();
function iterate(obj, stack) {
json="<ul>";
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property], stack + '.' + property);
}
else {
// console.log(property);
property_set.add(property);
json+="<li>";
if(typeof obj[property] !== "number") {
json+="<li>"+obj[property]+"</li>";
console.log(obj[property]);
}
}
} json += "</li>";
}
}
var listEl = document.getElementById('output');
iterate(jsonObj)
And this is the json format:
var jsonObj =
{
"level_1": [
{
"level_1_name": "CiscoSingaporeEBC",
"level_2": [
{
"level_2_name": "Khoo Tech Puat",
"level_2_id": 2222,
"level_3": [
{
"name": "Boon Leong Ong",
"id": 6919
},
{
"name": "Kiat Ho",
"id": 6917
},
{
"name": "Overall Experience",
"id": 6918
}
]
}
]
},
{
"level_1_name": "CiscoLondonEBC",
"level_2": [
{
"level_2_name": "Bernard Mathews Ltd.",
"level_2_id": 2367,
"level_3": [
{
"name": "Barry Pascolutti",
"id": 7193
},
{
"name": "Kathrine Eilersten",
"id": 7194
},
{
"name": "Martin Rowley",
"id": 7189
}
]
},
{
"level_2_name": "FNHW Day 1",
"level_2_id": 5678,
"level_3": [
{
"name": "Jurgen Gosch",
"id": 7834
},
{
"name": "Overall Experience",
"id": 7835
}
]
},
{
"level_2_name": "Groupe Steria Day 1",
"level_2_id": 2789,
"level_3": [
{
"name": "Adam Philpott",
"id": 7919
},
{
"name": "Pranav Kumar",
"id": 7921
},
{
"name": "Steve Simlo",
"id": 7928
}
]
}
]
}
]
};
enter code here
I'm not sure if I am interpretting your request correctly, but I think this is what you want: http://jsfiddle.net/mooreinteractive/43jh9hzz/1/
Basically, you are calling the iterate function to run, but then that's it. The function actually needs to also return the value it generates.
I've added to the end of the function, after the for loop completes:
return json;
Do now the function returns the value it generated, but there are some other issues too. When you recursively call the iterate function again inside the iterate function, you actually want to add what it returns to the current json string housing all of your returned value.
So on that line I changed it from:
iterate(obj[property], stack + '.' + property);
to
json += iterate(obj[property], stack + '.' + property);
Now that other value will come back as well inside the main list you were creating in the first run of the function. Ok so that's pretty close, but one more small thing. I think when you added additional surrounding LI, you actually wanted to do an UL. I changed those to ULs and now I think the result is like a UL/LI list representing the text parts of the JSON object.
Again, that may not be exactly what you were after, but I think the main take away is using the function to return the value, not just generate it, then do nothing with it.

Categories