How to change nested JSON value using stringify replacer? - javascript

I use JSON.stringify(value, replacer) to mask sensitive data in JSON object.
const inputJsonObject =
{
"id": "uniqueId",
"value": "objectData",
"user": {
"password": "qwerty"
}
};
const hideDataMethod = JSON.stringify(inputJsonObject, (key, value) => {
const dataToHide = ['id', 'user.password'];
return dataToHide.indexOf(key) === -1 ? value : 'xxx';
});
console.log(hideDataMethod);
How to get to user.password value? The above solution works for id but doesn't for password.

It doesn't work for password because you're looking for a property called "user.password", but there is none; the property's name is password, not user.password. (It's a property on an object that's referenced by the user property on another object, but that has nothing to do with the property name.) If you remove the user. part of that, it will work. Beware that doing it removes all id and password properties from all objects in the object graph being stringified:
const inputObject = {
"id": "uniqueId",
"value": "objectData",
"user": {
"password": "qwerty"
}
};
const dataToHide = ["id", "password"];
const json = JSON.stringify(inputObject, (key, value) => {
return dataToHide.indexOf(key) === -1 ? value : "xxx";
});
console.log(json);
(I also changed the name of a couple of variables that had misleading names.)
But I would sanitize it before converting it to JSON rather than during:
const tmp = {
...inputObject,
id: "xxx",
user: {
...inputObject.user,
password: "xxx",
}
};
const json = JSON.stringify(tmp);

Related

Getting error: Cannot read properties of undefined in javascript

While calling function getting error:
Uncaught TypeError: Cannot read properties of undefined (reading 'username')
at getLoginData (<anonymous>:3:30)
at <anonymous>:1:1"
role1 has value "administrator", but why it is not able to call in datamodel? (Datamodel here refers is another JSON file)
datamodel = {
administrator: [
{
username: "abc#xyz.com",
password: "abc#1234",
},
{
username: "abcd#xyz.com",
password: "xyz#1234",
},
],
};
function getLoginData(role1) {
console.log(role1);
let name = datamodel.role1.username;
}
getLoginData("administrator[0]");
You can't access object in that was, the code thinks that role1 is a key in that Object.
function getLoginData(role1){
console.log(role1)
let name=datamodel[role1][0].username
}
getLoginData("administrator")
var datamodel = {
"administrator": [
{
"username": "abc#io.com",
"password": "abc#1234"
},
{
"username": "xyz#io.com",
"password": "xyz#1234"
}
]
}
console.log(datamodel);
var name = datamodel.administrator[0].username; //get the name of administrator[0] = "rinty.kurian#espacenetworks.io"
console.log(name);
Try this :)
First of all you need to use Brackets Notation to access an object's attribute that is stored inside of another variable. So assuming you want the first credentials from the administrators array you would write something like datamodel.administrator[0].
Since, as it seems from your function's call, getLoginData('administrator[0]'), you would like that the function getLoginData to take care of accessing the inner administrators array which we cannot directly using brackets notation as datamodel['administrators[0]'] will raise an error because the attribute "administrators[0]" (string) doesn't exist in the datamodel object.
What we need to do is to try to extract the index of the items we want to return, if it exists, and then use that to return the right credentials from the datamodel object.
To do so, we will split the argument that is passed to getLoginData to get the attribute we want to access (ex: administrators) and the index (ex: 0).
Here's a live demo to implement such functionality:
const dataModel = {
"administrator": [{
"username": "abc#xyz.com",
"password": "abc#1234"
},
{
"username": "abcd#xyz.com",
"password": "xyz#1234"
}
]
},
/**
* a function that accepts an attribute name and optional index to get from "datamodel" object
*/
getLoginData = role => {
/**
* split the role parameter to get the wanted index if there is one
* the trick here is that we will replace the brackets around the index with a space and only keep the index itself (we'll get rid of those brackets)
* we should make some checks to prevent undefined index like errors
*/
const splitted = role.replace(/\[(\d+)\]/, ' $1').split(' '),
attr = dataModel[splitted[0]] ? (splitted.length > 1 ? dataModel[splitted[0]][splitted[1]] : dataModel[splitted[0]]) : null;
/** return the appropriete attribute or null if not defined */
return attr ? attr.username : null;
};
// prints: "abc#xyz.com"
console.log(getLoginData("administrator[0]"))
UPDATE
Here's another possible solution that works by passing the item index as the second parameter to datamodel object.
const dataModel = {
"administrator": [{
"username": "abc#xyz.com",
"password": "abc#1234"
},
{
"username": "abcd#xyz.com",
"password": "xyz#1234"
}
]
},
/**
* a function that accepts an attribute name and an index to get from "datamodel" object
*/
getLoginData = (role, index) => dataModel[role] && dataModel[role][index] ? dataModel[role][index].username : null;
// prints: "abc#xyz.com"
console.log(getLoginData("administrator", 0))

How to get JSON data with changing part of the call to get that data

I'm working on a side project of a currency converter. I've made an API Call and this is all the data it sent me (this varies depending on the selected currencies so USD_GBP could be CAD_JPY):
{
"query": {
"count": 1
},
"results": {
"USD_GBP": {
"id": "USD_GBP",
"val": 0.733695,
"to": "GBP",
"fr": "USD"
}
}
}
In my express code I've set up the HTTPS Module:
https.get(url, function(response) {
response.on("data", function(data) {
const currencyData = JSON.parse(data);
const exchangeRate = currencyData.results.USD_GBP.val;
});
});
});
The problem you can probably see is that since the currency to convert from and convert to are always changing the constant exchangeRate doesn't work for any scenario besides converting from USD to GBP. So I'm wondering how to make that work for every combination that I throw at it. Above my HTTPS get request I already made a variable (const combine = firstCurrency + "_" + secondCurrency;) that combines the selections. I tried concatenating it to the exchangeRate variable, but it gave me an error that it can't find the value of undefined.
JavaScript objects allow you to use bracket notation for dynamic variables names.
var obj = { bar: 'baz'; }
var foo = 'bar';
obj.foo ; // This is invalid, as it looks for the "foo" property
obj[foo]; // This is valid, as it looks for the "bar" property we want
Since you mentioned you have a variable named combine already, you should be able to use bracket notation on the results:
const exchangeRate = currencyData.results[combine].val;
Here's a quick little snippet:
var firstCurrency = 'USD';
var secondCurrency = 'GBP';
const combine = firstCurrency + "_" + secondCurrency;
var response = `{
"query": {
"count": 1
},
"results": {
"USD_GBP": {
"id": "USD_GBP",
"val": 0.733695,
"to": "GBP",
"fr": "USD"
}
}
}`;
const currencyData = JSON.parse(response);
const exchangeRate = currencyData.results[combine].val;
console.log( exchangeRate );
If you didn't have the combine variable, you could always use Object.keys() to get the keys from the result and use that, but it's arguably uglier (especially since you already know the key):
const exchangeRate = currencyData.results[Object.keys(currencyData.results)[0]].val;
Instead of currencyData.results.USD_GBP.val, use currencyData.results['USD_GBP'].val
You can even use a variable as well. :
currencies = ['USD_GBP', 'EUR_USD']
currenceis.forEach(currency => {
currencyData.results[currency].val
}
Changed Example:
https.get(url, function(response) {
response.on("data", function(data) {
const currencyData = JSON.parse(data);
const exchangeRate = currencyData.results['USD_GBP'].val;
});
});
});
You can use the backtick syntax.
let firstCurrency = "USD";
let secondCurrency = "GBP";
const currencyData = {
"query": {
"count": 1
},
"results": {
"USD_GBP": {
"id": "USD_GBP",
"val": 0.733695,
"to": "GBP",
"fr": "USD"
}
}
};
const exchangeRate = currencyData.results[`${firstCurrency}_${secondCurrency}`].val;
console.log(exchangeRate);

Make a nested loop for a JSON object in nodejs

Hi I'm new to React and nodejs. I get from the user his preferences for certain categories in the json code for example:
{
"sport" : {
"tennis": "5",
"running": "4",
"swimming": "5"
},
"study" : {
"history" : "0"
}
}
I want for each preference to create its own field in the "userPreferences" object.
This is the code I wrote down but I can not see what the error is here
exports.reduceUserPreferences = (data) => {
let userPreferences = {};
data.forEach(category => {
category.forEach(preference => {
category_preference_name = category.string + "_" + preference.string;
if (!isEmpty(preference.trim())) userPreferences.category_preference_name = preference;
});
});
//if (!isEmpty(data.tennis.trim())) userPreferences.sport_tennis = data.tennis;
//if (!isEmpty(data.swimming.trim())) userPreferences.sport_swimming = data.swimming;
//if (!isEmpty(data.running.trim())) userPreferences.sport_running = data.running;
//if (!isEmpty(data.history.trim())) userPreferences.study_history = data.history;
return userPreferences;
};
I want the "" object to have fields of all preferences along with the category to which they belong.
I can not understand what I am doing wrong, I linger on this code for several hours.
add example
I have another function similar to this function, the input is similar and the output is similar.
For example input:
{
"bio": "hello there",
"website": "",
"location": "los angles"
}
Example function:
exports.reduceUserDetails = (data) => {
let userDetails = {};
if (!isEmpty(data.bio.trim())) userDetails.bio = data.bio;
if (!isEmpty(data.website.trim())) {
// https://website.com
if (data.website.trim().substring(0, 4) !== 'http') {
userDetails.website = `http://${data.website.trim()}`;
} else userDetails.website = data.website;
}
if (!isEmpty(data.location.trim())) userDetails.location = data.location;
return userDetails;
};
The output will be:
An object with the attribute of all preferences along with their value.
I was looking for examples with a nested loop, I could not find.
There are a couple of things you need to fix in your code.
First, when using a variable name as the key to extract from an object, user obj[varName], not obj.varName.
(read more here: Dynamically access object property using variable)
Also, you're trying to loop an Object, not an array. To loop through the keys, use Object.keys()
Combining these two things you get the desired result, as you can see in this snippet. Also, for future questions, I highly recommend you make a snippet yourself.
const jsonOriginal = {
"sport" : {
"tennis": "5",
"running": "4",
"swimming": "5"
},
"study" : {
"history" : "0"
}
}
const reduceUserPreferences = (data) => {
let userPreferences = {};
Object.keys(data).forEach(category => {
Object.keys(data[category]).forEach(preference => {
category_preference_name = category + "_" + preference;
const preferenceValue = data[category][preference].trim();
if (preferenceValue !== '') userPreferences[category_preference_name] = preferenceValue;
});
});
return userPreferences;
};
console.log(reduceUserPreferences(jsonOriginal))

Deleting json value with javascript

I have tried to many ways , but i am stuck with a simple function in javascript, and i don't know where i need to looking for ... the problem is this:
I have a Json file like this one:
{
"blacklist": [
{
"email": "strangemail#gmail.com"
},
{
"email": "strangemail1#gmail.com"
},
{
"email": "strangemail2#gmail.com"
},
{
"email": "fianlt#gmail.com"
},
{
"email": "finalstatustest#gmail.com"
}
]
}
I would like simple remove an email with a simple function like this one:
function cancel(email) // parameter that contain the value to delete
{
let rawdata = fs.readFileSync('pvt.json'); //get local json file
let mydata = JSON.parse(rawdata); //parsing rawdata
var key = email; //setting up key
delete mydata.blacklist[key]; //using delete function for delete an element
let data = JSON.stringify(mydata, null, 2); //stringify the result
fs.writeFileSync('pvt.json', data); // overwrite local file with new one with all changes
}
the problem is ... it doesn't works ... i don't know why ... i tried to read the documentation, but i didn't found any solution 😢
The delete operator is for removing a property from an object, using the property's name. You're trying to remove an entry from an array, using the value of a property of an object in the array.
Assuming email is a variable containing the email address in the entry you want to remove, filter is one easy way to do that:
mydata.blacklist = mydata.blacklist.filter(entry => entry.email !== email);
filter builds a new array from the entries in the original array that meet the criteria in the callback — in this case, that their email property doesn't match the email address you want to remove.
If you wanted to modify the array in place rather than creating a new one, you'd use findIndex and splice:
const index = mydata.blacklist.findIndex(entry => entry.email === email);
if (index !== -1) {
mydata.blacklist.splice(index, 1); // Remove the entry at the index
}
Delete works to delete a key-value from an object. Here you have an array of items[objects]. You should use filter to remove unwanted element.
Update:
function cancel(selectedEmail) {
let rawdata = fs.readFileSync("pvt.json"); //get local json file
let mydata = JSON.parse(rawdata); //parsing rawdata
mydata.blacklist = mydata.blacklist.filter(
(item) => item.email !== selectedEmail.email
);
fs.writeFileSync("pvt.json", JSON.stringify(mydata, null, 2)); // overwrite local file with new one with all changes
}
Sample:
const info = {
blacklist: [
{
email: "strangemail#gmail.com",
},
{
email: "strangemail1#gmail.com",
},
{
email: "strangemail2#gmail.com",
},
{
email: "fianlt#gmail.com",
},
{
email: "finalstatustest#gmail.com",
},
],
};
const selectedEmail = {email: "finalstatustest#gmail.com"}
info.blacklist = info.blacklist.filter(item => item.email !== selectedEmail.email)
console.log(info)

JavaScript - Replace the values of a Nested Object, without affecting the whole object

The Problem:
I have this function. Which removes all KeyValue Pairs that have an Empty String as value from a Payload.
The problem is, that I want to apply it in an Object that is Nested. Not the whole Payload Object. Example:
configuration: {
conf1: "",
conf2: "Something",
conf3: ""
},
resourceName: "Name"
In this case I want to apply my UtilityFunction, in the configurationObject. Which would result in this:
configuration: {
conf2: "Something",
},
resourceName: "Name"
So, I used a few Methods. Object.assign, rest, in order to supply an object with all the outside parameters, but also, the output of the utility applied to just the configuration object.
I tried:
Object.assign(formValues, removeEmptyKeysUtil(formValues.configuration));
// Results in printing the values in the main object.
Also:
{ formValues, ...removeEmptyKeysUtil(formValues.configuration) };
// which does not do anything
Can you please help me, and explain what am I doing wrong?
The stripEmptyStrings function takes the original object and the target key.
this function can also handle if the target property of the object is "" and will delete that property regardless of if it is an Object or not.
const stripEmptyStrings = (object, target) => {
const _target = object[target];
if (_target === "") {
delete object[target]
return object;
}
else if (typeof _target === "object") {
Object.keys(_target).forEach((k) => {
if (_target[k] === "") delete _target[k];
})
}
return {
...object,
[target]: _target,
}
}
const obj1 = {
configuration: {
conf1: "",
conf2: "Something",
conf3: ""
},
resourceName: "Name",
}
const result1 = stripEmptyStrings(obj1, "configuration");
console.log(result1)
const obj2 = {
removeMe: "",
resourceName: "Name2",
}
const result2 = stripEmptyStrings(obj2, "removeMe");
console.log(result2)

Categories