MongoDB + Mongoose:仅当给定键不存在或具有虚假值时才设置

Posted

技术标签:

【中文标题】MongoDB + Mongoose:仅当给定键不存在或具有虚假值时才设置【英文标题】:MongoDB + Mongoose: $set only if given key does not exist or have falsy value 【发布时间】:2016-07-30 07:00:06 【问题描述】:

我需要有关 findOneAndUpdate(upsert: true) 查询的帮助:

得到了这个模式:

    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: 
        
    

当用户是新用户时,使用 facebook(使用 passportjs)创建帐户,firstName、lastName、email 等的数据将填充 facebook 检索到的数据。如果用户通过本地策略创建了他的帐户,则这些字段可能不存在,并且在他第一次使用 facebook 登录时,它们会被填充(更新个人资料)。

完美。

现在让我们说,用户通过在线表格手动更新他的个人资料,在他第一次使用 facebook 登录之前,并设置一个电子邮件地址(不同于与他的 facebook 帐户关联的)。

当他用他的 facebook 登录时,电子邮件地址将被从他的 facebook 帐户中检索到的电子邮件地址覆盖。

有没有办法将 findOneAndUpdate() 方法设置为只插入不存在的键(或者可能是给定键默认值的值)?

可能以某种方式将 $set 与 $exists 运算符结合起来(我试过这个,但找不到正确的语法)

我使用的查询如下:

    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)
        );

谢谢大家!

【问题讨论】:

【参考方案1】:

没有条件$set,但是,如果用户已经创建了一个帐户并且他必须在他这样做时提供他的电子邮件,那么使用 Facebook 登录不应该覆盖它,这表示您可以从$set 操作员中删除电子邮件。

一旦你有了这个,你就会看到用户尚未注册的用例(upsert),在这种情况下,你可以使用$setOnInsert 来设置电子邮件。

【讨论】:

实际上,您的回答解决了电子邮件问题,但我的问题对用户名、姓氏等仍然有效。如果用户仅使用电子邮件和密码创建帐户,则通过表单更新他的个人资料,然后用 facebook 登录,它会覆盖所有这些信息(这可能是不受欢迎的)。任何想法? @arg20 不错,看来您必须先获取模型。如果不先查询数据库,我想不出办法。这也不是最糟糕的,稍后您可能希望在模型中存储用户登录时需要的数据。无论他们的帐户是否已激活或登录计数等。

以上是关于MongoDB + Mongoose:仅当给定键不存在或具有虚假值时才设置的主要内容,如果未能解决你的问题,请参考以下文章

在 Mongoose/MongoDB 的文档中过滤数组、子文档、数组、文档

使用 Mongoose 查找子文档字段部分匹配给定条件的文档

使用 Mongoose 查找子文档字段部分匹配给定条件的文档

如何连接到最新的 Mongoose 版本

使用 Mongoose 和 Redux 删除记录

关于NodeJs为啥要用mongoose操作mongodb