Omit object's key-value if value == null [duplicate] - javascript

This question already has answers here:
In JavaScript, how to conditionally add a member to an object?
(29 answers)
Closed 2 years ago.
Having typescript code presented below, which creates new record in the Firestore database, is it possible to omit (by writing one line of inline code) one of the key-value pair if the value equals null?
firestore.doc(`users/${user.uid}`).set({
email: user.email,
name: user.displayName,
phone: user.phoneNumber, // (user.phoneNumber ? phone: user.phoneNumber), ... ?
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
});

You can use the object destruction with ternary expression to do it:
firestore.doc(`users/${user.uid}`).set({
email: user.email,
name: user.displayName,
...(user.phoneNumber ? { phone: user.phoneNumber } : undefined),
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
});
It's not very elegant, but it get its job done in one line:
const phone = null;
const obj = {
name: 'Alice',
age: 24,
...(phone ? { phone } : undefined),
};
console.log(obj);
Edit
According to this answer that ford04 mentioned, it also can be shortened like this:
...(user.phoneNumber && { phone: user.phoneNumber }),
Edit, again
But it's better to check its type properly that it might cause 0 and "" are not stored correctly
...(![undefined, null].includes(user.phoneNumber) && { phone: user.phoneNumber })

Related

dynamically merging(override) 2 javascript objects [duplicate]

This question already has answers here:
How to deep merge instead of shallow merge?
(47 answers)
Merge two objects and overwrite the values if conflict
(4 answers)
Closed 2 years ago.
I have 2 objects .
userprofile = {
id: 1,
email: hello #gmail.com,
user: {
id: 1,
username: test,
}
}
userprofile2 = {
email: bye #gmail.com,
user: {
username: testtest,
}
}
What i wish to do is to merge userprofile and userprofile2 , or in a sense using userprofile2 to override userprofile.
Here is what i wish to obtain:
updatedprofile = {
id: 1,
email: bye #gmail.com,
user: {
id: 1,
username: testtest,
}
}
The application for this problem is because i have an update form which uses redux saga . The change in data is userprofile2 while the previous data is userprofile.
Is there a simple efficient way to do this?
You could use the spread operator. As the ... operator only performs a shallow merge, you will have to spread the nested user property as well.
const userprofile = {
id: 1,
email: "hello #gmail.com",
user: {
id: 1,
username: "test",
}
}
const userprofile2 = {
email: "bye #gmail.com",
user: {
username: "testtest",
}
}
const updatedProfile = {
...userprofile,
...userprofile2,
user: {
...userprofile.user,
...userprofile2.user,
}
};
console.log(updatedProfile)

Removing all objects that have a property/value duplicate BUT the last [duplicate]

This question already has answers here:
Javascript es6 - How to remove duplicates in an array of objects, except the last duplicate one?
(3 answers)
Closed 3 years ago.
I need to loop through an array of objects where each object will have an email property. My goal is to loop through the data (CSV) and if any record has the same email, I need to remove all but the last as that will be the value that I need to update in the end. I can't seem to get this right.
I have tried using .find but I never quite made it all the way. I feel like I need to add to it but I'm hazy as to what.
let arr = [
{name: 'stefano', email: 'stef#mail.com'},
{name: 'steve', email: 'cuck#mail.com'},
{name: 'weave', email: 'stef#mail.com'},
{name: 'peave', email: 'luck#mail.com'}
];
let keepLast = arr.find( (obj,idx) => {
let found = 0;
if(obj.email === 'stef#mail.com') {
++found;
}
if(found > 1) {
// Somehow remove the previous iteration catch on match
}
});
This is about where I am. I feel like I need to somehow keep memory of the last index so I know to remove it as soon as I find another one.
I'd reduce into an object indexed by the email, thereby overwriting the previous object at that email key if it exists. Then just take that object's values:
let arr = [
{name: 'stefano', email: 'stef#mail.com'},
{name: 'steve', email: 'cuck#mail.com'},
{name: 'weave', email: 'stef#mail.com'},
{name: 'peave', email: 'luck#mail.com'}
];
const output = Object.values(
arr.reduce((a, obj) => {
a[obj.email] = obj;
return a;
}, {})
);
console.log(output);

Typescript - Conditional property of object

I have the following object to which I wish to have a conditional property:
{ name: this.username, DOB: new Date(this.inputDate)}
Say, I wish to add a third property called gender if the user has specified their gender. What would the proper syntax for the following be:
{ name: this.username, DOB: new Date(this.inputDate), if(this.userGender) gender: this.userGender}
P.S. I do not wish to have the gender property in my object if there is no value along with it. So how can I only create the property if the condition is satisfied?
Ideally, you would just add the appropriate property as a second action after declaring your object. So something like:
const myObj = {
name: this.username,
DOB: new Date(this.inputDate),
}
if(this.userGender) myObj.gender = this.userGender;
However, sometimes it's nice to declare an "optional" property inline with the rest of them, in which case you can use object spread to get the effect you're looking for:
const myObj = {
name: this.username,
DOB: new Date(this.inputDate),
...this.userGender
? { gender: this.userGender }
: {}
}
it can be done like this too, more clean and readable.
const myObj = {
name: this.username,
DOB: new Date(this.inputDate),
...(this.userGender && { gender : this.userGender })
}
Try this
let userObj = { name: this.username, DOB: new Date(this.inputDate) }
if(this.userGender)
userObj[:gender] = this.userGender;

How to check two objects for difference in values in JS?

I want to edit a existing user in Node. My front-end is in pug.
My user table has lots of fields (about 20 to 25), and some have to be unique, like email and username, which I have functions to check if they are not a duplicate.
I only want to update values that has changed on the client, my edit form already has the values of the user of course.
I thought the best way to achieve this is to check all the inputs from req.body, and if it is different from any user values, I should update it. (Perhaps any different methods? Can't I check if the inputs are 'dirty'?)
This could be the situation. Note the req.body object, with values that my user table doesn't have, like password_confirm
req.body = {
username: 'test',
email: 'user#user.com',
password: '1234',
password_confirm: '1234',
location: 'New York',
website: 'new-website.com',
bio: undefined,
expertise: 'New expertise'
}
user = {
username: 'test',
email: 'user#user.com',
password: '1234',
location: 'San Fransico',
website: 'website.com',
bio: null,
expertise: null
}
I now only want to update the changed location, website and expertise fields. I tried many things, using reduce and lodash, but I can't get the fields that I'm looking for.
NB
I already checked different StackOverflow questions but nothing seems to work for my situation..
From what I understood from your question, give this a try,
Object.keys(req.body).forEach((key)=>{
if(user[key] && user[key]!=req.body[key]){
user[key] = req.body[key];
}
})
Well, I think you are over complicating. You don't even need lodash for this.
Object.assign({}, user, req.body);
would work, since you said yourself that you can have different fields in req.body.
If you need diff object use this:
function diff(oldObject, newObject) {
const diff = {};
Object.keys(oldObject).forEach((key) => {
if (oldObject[key] != newObject[key] && newObject[key] !== undefined) {
diff[key] = newObject[key];
}
});
return diff;
}
var body = {
username : 'test',
email : 'user#user.com',
password : '1234',
password_confirm : '1234',
location : 'New York',
website : 'new-website.com',
bio : undefined,
expertise : 'New expertise'
}
var user = {
username : 'test',
email : 'user#user.com',
password : '1234',
location : 'San Fransico',
website : 'website.com',
bio : null,
expertise : null
}
function diff(oldObject, newObject) {
const diff = {};
Object.keys(oldObject).forEach((key) => {
if (oldObject[key] != newObject[key] && newObject[key] !== undefined) {
diff[key] = newObject[key];
}
});
return diff;
}
console.log(diff(user, body));
I figured it out.
Based on #ponary-kostek & #anuragasaurus 's answer, this is what worked for me:
const differences = {};
Object.keys(req.body).forEach((key)=> {
if(req.body[key].length == 0) req.body[key] = null;
if(stakeholder.hasOwnProperty(key) && stakeholder[key]!=req.body[key]){
differences[key] = req.body[key];
}
});
This returns an object with the changed keys and their values.
Because the fields from my user object are retrieved from a SQL DB, they are null. Also, empty body fields are not undefined, but strings. Meaning if the input is empty, it is an empty string, and to compare it to my user object it should first be null.
Thanks everyone for their answers.

Check if property is not undefined

I'm building a node+express app and I'm filling an object with JSON that's submitted from a form in the frontend. This works, unless I leave a field empty in the form so that e.g. req.body.address.street is empty/undefined.
This will result in the error:
TypeError: Cannot read property 'street' of undefined
var b = new Business({
name: req.body.name,
phone: req.body.phone,
address: {
street: req.body.address.street,
postalCode: req.body.address.postalCode,
city: req.body.address.city
},
owner: {
email: req.body.owner.email,
password: req.body.owner.password
}
});
My question is how I can best prevent my app from crashing when values are empty. I would like to avoid manually checking each and every property in my app against undefined.
I'm wondering what the best practice is for this common issue.
I don't know if you use jQuery in your project, but if you do, you can create a mask:
// creating your object mask
var req = {
body: {
name: '',
phone: '',
address: {
street: '',
postalCode: '',
city: ''
},
owner: {
email: '',
password: ''
}
}
}
And then, you simply use the jQuery "extend" method (req2 is your submmited object):
$.extend(true, req, req2);
I've create this fiddle for you!
-
Update
Nothing related to your question, but I've just noticed that you're passing an object with a similar structure of req.body to the Business class. However, there is no need to copy property by property manually - you can make, for example, a simple copy of req.body to pass as parameter:
var b = new Business($.extend({}, req.body));
or
var b = new Business(JSON.parse(JSON.stringify(req.body)));
You can't, really. You have two options;
Use a try/ catch:
try {
var b = new Business({
//
});
} catch (e) {
// Something wasn't provided.
}
... or you can define a helper function:
function get(path, obj) {
path = path.split('.');
path.shift(); // Remove "req".
while (path.length && obj.hasOwnProperty(path[0])) {
obj = obj[path.shift()];
}
return !path.length ? obj : null;
}
... you could then replace your use of req.body.address.street etc. with get('req.body.address.street', req).
See a demo here; http://jsfiddle.net/W8YaB/

Categories