简体   繁体   中英

MongoDB + Mongoose: $set only if given key does not exist or have falsy value

I need a help on a findOneAndUpdate({upsert: true}) query:

got this shchema:

    usersSchema = new Schema(
    {
        name: {type: String, unique: true, uniqueCaseInsensitive: true},    // username
        password: {type: String, minlength: 4},
        slug: {type: String, unique: true, uniqueCaseInsensitive: true},    // ok - Automatic on backend - based on name
        firstName: {type: String},
        middleName: {type: String},
        lastName: {type: String},
        email: {type: String, unique: true, uniqueCaseInsensitive: true},
        //country: {type: String, required: true, minlength: 3}
        socialIDs: {
            facebook: {
                id: {type: String, unique: true}
            },
            twitter: {},
            google: {}
        }
    }

when user is new, creating account using facebook (with passportjs), the data of firstName, lastName, email, etc are populated with facebook retrieved data. if the user has created his account via local strategy, those fields may be non-existent and, the first time he log in with facebook, they got populated (updating profile).

perfect.

lets say now, the user update manually his profile via online form, BEFORE log in with facebook his first time, and set up a e-mail address (different from the associated with his facebook account).

when he log in with his facebook, the email address will be overwritten with the one retrieved from his facebook account.

is there a way to set the findOneAndUpdate() method to only insert keys that are non-existent (or maybe values on given key default falsy value)?

maybe combining $set with $exists operators somehow (I have tried this, but could not figure out correct syntax)

the query I am using is the following:

    User.findOneAndUpdate(
        {
            $or: [
                {email: profile._json.email},
                {socialIDs: {facebook: {id: profile._json.id}}}
            ]
        },
        {
            $set: {
                firstName: profile._json.first_name,
                middleName: profile._json.middle_name,
                lastName: profile._json.last_name,
                avatar: profile._json.picture,
                gender: profile._json.gender,
                email: profile._json.email,
                socialIDs: {
                    facebook: {
                        id: profile._json.id,
                        profileLink: profile._json.link,
                    }
                }
            }
        },
        {new: true, upsert: true},
        function(err, user){
            done(err, user)
        });

thanks guys!

there's no conditional $set , however, if the user has already created an account and he has to provide his email when he does, then logging in with Facebook shouldn't overwrite it, which means you can remove the email from the $set operator.

Once you have this, you are left with the use case where a user has not signed up yet (upsert), in that case, you can use $setOnInsert to only in that scenario set the email.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM