Simplify javascript object creation using ES6 destructuring - javascript

Is there a way to simplify the update of the user object using destructuring where I have an old object and I want to update to the new object with the same names for the properties.
I want to use the same user object and update the values rather than creating a new object.
function UpdateUserProps(user, updatedUser) {
const { email, status } = updatedUser;
user.email = email;
user.status = status;
return user;
}

You could use spread syntax ... in object. This creates a new object.
function UpdateUserProps(user, updatedUser) {
return {...user, ...updatedUser}
}
You can also use parameter destructuring to take specific properties from update object.
function UpdateUserProps(user, {email, status}) {
return {...user, ...{email, status}}
}
let user = {
name: "foo",
email: "foo",
status: true
}
console.log(UpdateUserProps(user, {
email: "bar",
status: false
}))

You could do it without destructuring as well using Object.assign
function updateUserProps(user, updatedUser) {
return Object.assign({}, user, updatedUser);
}
If you want to update in the same user object
function updateUserProps(user, updatedUser) {
return Object.assign(user, updatedUser);
}

Related

how to transform value string in object to new const js

i need to convert a object with have key value to new object that contain new const named form platform and have name to value in js how to do it?
posters: [
{ platform: facebook; name: ["user test1","user test2"] },
{ platform: instagram; name: ["Ig test1","Ig test2"] },
]
in to
posters: {
facebook: ["user test1","user test2"] ,
instagram: ["Ig test1","Ig test2"] ,
}
Your input array is invalid. There are no strings around your platform values, and you're separating your object properties with a semi-colon rather than a comma. So you would need to fix that in order to proceed.
It looks as if posters is a property within a larger object so this answer will take that into account.
Use reduce on the posters array to iterate over the objects in the array and return an object where the keys are the platform names, and the values the name arrays.
Since it looks like posters is within a larger object we'll rebuild the object using the spread syntax.
const data={posters:[{platform:"facebook",name:["user test1","user test2"]},{platform:"instagram",name:["Ig test1","Ig test2"]}]};
// Create a new object
const updated = {
// Spread out the old object into it
...data,
// And replace the old `posters` property with an
// object using `reduce`. Destructure the `platform`
// and `name` properties from the object, and then
// use them to add a key and a value to the initial
// object (`acc`/accumulator)
posters: data.posters.reduce((acc, obj) => {
const { platform, name } = obj;
acc[platform] = name;
return acc;
}, {})
};
console.log(updated);
Additional documentation
Destructuring assignment
const postersArray = [
{ platform: facebook, name: ["user test1","user test2"] },
{ platform: instagram, name: ["Ig test1","Ig test2"] }
]
const postersObject = postersArray.reduce((previous, current) => {
return {
…previous,
[current.platform]: current.name
}
},{})

Javascript object declaration with ternary operator

I'm declaring an object inside one of my components like below:
const data = {
user: id,
userRole: role,
teacherdepartment: department
}
But now I wanted to do this declaration dynamically depends on a specific value, like below:
let usertype='teacher';
const data = {
user: id,
userRole: role,
if(usertype=='teacher'?(teacherdepartment:tdepartment):(studentDepartment:sdepartment))
}
Is this possible. I know I can do it with nested ternary operator. But inside the object structure any simple line that can do that trick?
Update: object values can be easily set using ternary inside the object declaration, but this is for object key so this is not a duplicate of this. Also, in the above example I have put a simple object. Image if the objects have some child and ternary conditions within.
I think this could be refactored into
let usertype = 'teacher';
let departmentProperty = usertype === 'teacher' ? 'teacherdepartment' : 'studentDepartment';
let departmentValue = usertype === 'teacher' ? 'teacherdepartmentValue' : 'studentDepartment';
const data = {
user: 'id',
userRole: 'role',
[departmentProperty]: departmentValue,
};
console.log(data)
Try with conditional operator for both key and value. Keys can be made dynamic by adding [] around the key expression.
Pseude Code
const data = {
user: id,
userRole: role,
[usertype=='teacher'? 'teacherdepartment' : 'studentDepartment']: usertype=='teacher'? tdepartment: sdepartment,
}
Working Code
const usertype = 'student';
const tdepartment = 'tdepartment';
const sdepartment = 'sdepartment';
const id = 'id';
const role = 'role';
const data = {
user: id,
userRole: role,
[usertype=='teacher'? 'teacherdepartment' : 'studentDepartment']: usertype=='teacher'? tdepartment: sdepartment,
};
console.log(data)
I'd avoid a ternary operator altogether because they're confusing to read in a lot of situations. Instead I would create a dictionary that maps user types to string values, and then create the property dynamically with that information.
const userType = 'teacher';
const dict = { teacher: 'tdepartment', student: 'sdepartment' };
const data = {
user: 'id',
userRole: 'role',
[`${userType}Department`]: dict[userType]
}
console.log(data);
While this can be done in a "one-liner" IMO to preserve readability it shouldn't be.
Instead, check usertype and create an object to include in the resulting data object. This way the changes based on usertype are isolated and easy to reason about. It also allows for additional changes based on usertype as it's isolated from the static properties.
const deptInfo = usertype === 'teacher' ? { teacherDepartment: tDepartment }
: { studentDepartment: sDepartment }
const data = {
...deptInfo,
user: id,
userRole: role,
}

React object property value being duplicated on .push inside loop

I have a handleCreate function that takes care of taking some user data and inserting it into a database.
Inside the aliasArr.forEach() loop I POST into my DB new user instances for each element in the aliasArr array. This particular code works as expected, if I check the DB, I will find the new members.
After saving the new members, I want to keep the members in the members array so I can pass it along to another function.
For this, I'm doing members.push(memberAttributes); but if I log the contents of members I get the right amount of elements but the alias property value is duplicated (all other properties should have the same value cause they are being added into the same role in a batch operation).
If I have two new users, say: xyz and abc, I get:
[
{alias: "abc", Role: "admin", "grantedBy": "someone"},
{alias: "abc", Role: "admin", "grantedBy": "someone"},
]
Instead of:
[
{alias: "xyz", Role: "admin", "grantedBy": "someone"},
{alias: "abc", Role: "admin", "grantedBy": "someone"},
]
Here's the code:
handleCreate = () => {
const { memberAttributes } = this.state;
const { role, createRoleMember } = this.props;
const roleArr = [];
roleArr.push(role);
const aliasArr = memberAttributes.alias.split(",");
let members = [];
//false hardcoded during debugging.
if (false /* await aliasIsAdmin(memberAttributes.alias, roleArr) */) {
this.setState({ userExists: true });
} else {
memberAttributes["Granted By"] = window.alias;
memberAttributes.Role = role;
memberAttributes.timestamp = Date.now().toString();
this.handleClose();
aliasArr.forEach((currAlias) => {
memberAttributes.alias = currAlias;
console.log("memberAttributes:", memberAttributes);
members.push(memberAttributes);
console.log("members", members);
const marshalledObj = AWS.DynamoDB.Converter.marshall(memberAttributes);
const params = {
TableName: "xxx",
Item: marshalledObj,
};
axios.post(
"https://xxx.execute-api.us-west-2.amazonaws.com/xxx/xxx",
params
);
});
}
createRoleMember(members); //passing members to this function to do more stuff.
};
I'm wondering if this issue is due to memberAttributes being part of the component's state.
The problem here is that you are pushing references to the same object into the array after changing a value within that object. So whenever you make the change to memberAttributes.alias, it's changing the alias to the most recent one. After that, all references to the same object (which in this case is every item in the members array) present the new value in alias.
const obj = { alias: 'abc', role: 'role1' }
const arr = []
arr.push(obj)
obj.alias = 'new alias'
arr.push(obj)
for (var mem of arr) {
console.log(mem)
}
To fix it, you need to create a new object each time and push it onto the array instead, like so:
aliasArr.forEach((currAlias) => {
// Creates a new object in memory with the same values, but overwrites alias
const newMemberAttributes = Object.assign(memberAttributes, { alias: currAlias });
console.log("memberAttributes:", newMemberAttributes);
members.push(newMemberAttributes);
console.log("members", members);
...
}
Similarly, you can use the spread operator to create a deep copy of the object and then reassign alias.
aliasArr.forEach((currAlias) => {
// Creates a new object in memory with the same values, but overwrites alias
const newMemberAttributes = { ...memberAttributes };
newMemberAttributes.alias = currAlias
console.log("memberAttributes:", newMemberAttributes);
members.push(newMemberAttributes);
console.log("members", members);
...
}

How to prepare the object before request to be compatible with the requirements of the service?

When the service requires an object like in method to change name:
{
user: {
data: {
name: string
}
}
}
but, I have object like
{
user: {
age: 18,
height: 150,
weight: 80
data: {
name: 'John',
surname: 'Juhn'
}
}
}
How do I prepare for an object to be compatible with service?
remove unwanted properties with a copy of an object in order not to lose data?
eg.
export function removeUnnecessaryProperty(object: Object, ...necessaryKeys: string[]) {
Object.keys(object).forEach(key => {
if (necessaryKeys.indexOf(key) < 0) { delete object[key]; };
});
}
let objectToRequest = JSON.parse(JSON.stringify(object));
removeUnnecessaryProperty(objectToRequest.data, 'name');
removeUnnecessaryProperty(objectToRequest, 'data');
create a new object only with the required properties?
eg.
export function createObjectWithProperty(object: Object, ...Keys: string[]) {
let newObject: Object = {};
Keys.map(key => {
newObject[key] = object[key];
});
return newObject
}
let objectToRequest = {data: undefined}
objectToRequest.data = createObjectWithProperty(object.data, 'name');
or send an object with additional properties?
Of course you need to pass the exact number of properties.
Why? Don't pass any data that your service doesn't require. Besides this if an hacker can catch your data, he/she will get only that data, not all data.
Think a case when I need to pass only user's name to my Web Api. But my object contains also the email. Why the hacker need also get the email? With name he can't do anything, but with mail he can do many other things.

Why can't I delete a mongoose model's object properties?

When a user registers with my API they are returned a user object. Before returning the object I remove the hashed password and salt properties. I have to use
user.salt = undefined;
user.pass = undefined;
Because when I try
delete user.salt;
delete user.pass;
the object properties still exist and are returned.
Why is that?
To use delete you would need to convert the model document into a plain JavaScript object by calling toObject so that you can freely manipulate it:
user = user.toObject();
delete user.salt;
delete user.pass;
Non-configurable properties cannot be re-configured or deleted.
You should use strict mode so you get in-your-face errors instead of silent failures:
(function() {
"use strict";
var o = {};
Object.defineProperty(o, "key", {
value: "value",
configurable: false,
writable: true,
enumerable: true
});
delete o.key;
})()
// TypeError: Cannot delete property 'key' of #<Object>
Another solution aside from calling toObject is to access the _doc directly from the mongoose object and use ES6 spread operator to remove unwanted properties as such:
user = { ...user._doc, salt: undefined, pass: undefined }
Rather than converting to a JavaScript object with toObject(), it might be more ideal to instead choose which properties you want to exclude via the Query.prototype.select() function.
For example, if your User schema looked something like this:
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
},
name: {
type: String,
required: true
},
pass: {
type: String,
required: true
},
salt: {
type: String,
required: true
}
});
module.exports = {
User: mongoose.model("user", userSchema)
};
Then if you wanted to exclude the pass and salt properties in a response containing an array of all users, you could do so by specifically choosing which properties to ignore by prepending a minus sign before the property name:
users.get("/", async (req, res) => {
try {
const result = await User
.find({})
.select("-pass -salt");
return res
.status(200)
.send(result);
}
catch (error) {
console.error(error);
}
});
Alternatively, if you have more properties to exclude than include, you can specifically choose which properties to add instead of which properties to remove:
const result = await User
.find({})
.select("email name");
The delete operation could be used on javascript objects only. Mongoose models are not javascript objects. So convert it into a javascript object and delete the property.
The code should look like this:
const modelJsObject = model.toObject();
delete modlelJsObject.property;
But that causes problems while saving the object. So what I did was just to set the property value to undefined.
model.property = undefined;
Old question, but I'm throwing my 2-cents into the fray....
You question has already been answered correctly by others, this is just a demo of how I worked around it.
I used Object.entries() + Array.reduce() to solve it. Here's my take:
// define dis-allowed keys and values
const disAllowedKeys = ['_id','__v','password'];
const disAllowedValues = [null, undefined, ''];
// our object, maybe a Mongoose model, or some API response
const someObject = {
_id: 132456789,
password: '$1$O3JMY.Tw$AdLnLjQ/5jXF9.MTp3gHv/',
name: 'John Edward',
age: 29,
favoriteFood: null
};
// use reduce to create a new object with everything EXCEPT our dis-allowed keys and values!
const withOnlyGoodValues = Object.entries(someObject).reduce((ourNewObject, pair) => {
const key = pair[0];
const value = pair[1];
if (
disAllowedKeys.includes(key) === false &&
disAllowedValues.includes(value) === false
){
ourNewObject[key] = value;
}
return ourNewObject;
}, {});
// what we get back...
// {
// name: 'John Edward',
// age: 29
// }
// do something with the new object!
server.sendToClient(withOnlyGoodValues);
This can be cleaned up more once you understand how it works, especially with some fancy ES6 syntax. I intentionally tried to make it extra-readable, for the sake of the demo.
Read docs on how Object.entries() works: MDN - Object.entries()
Read docs on how Array.reduce() works: MDN - Array.reduce()
I use this little function just before i return the user object.
Of course i have to remember to add the new key i wish to remove but it works well for me
const protect = (o) => {
const removes = ['__v', '_id', 'salt', 'password', 'hash'];
m = o.toObject();
removes.forEach(element => {
try{
delete m[element]
}
catch(O_o){}
});
return m
}
and i use it as I said, just before i return the user.
return res.json({ success: true, user: await protect(user) });
Alternativly, it could be more dynamic when used this way:
const protect = (o, removes) => {
m = o.toObject();
removes.forEach(element => {
try{
delete m[element]
}
catch(O_o){}
});
return m
}
return res.json({ success: true, user: await protect(user, ['salt','hash']) });

Categories

Resources