谷歌账号二次登录触发MongoError: E11000重复键错误问题咨询
问题原因
- 你引入的
passport-local-mongoose插件默认会给username字段创建全局唯一索引,不允许集合中出现重复的username值 findOrCreate方法的第一个参数是查询匹配条件,你当前把username、myCollection、games等非唯一标识字段都放到了查询条件中,只要任意一个字段的值和数据库中已存的同googleId用户的字段值不一致,就会判定为用户不存在,尝试创建新用户,进而触发username重复的唯一索引报错- 你代码中的
catalogDb变量如果在首次登录后发生过变更,也会导致查询匹配失败,触发重复创建逻辑
解决方案
方案1:修正findOrCreate的参数逻辑(推荐)
仅使用谷歌账号唯一标识googleId作为查询条件,其余字段作为创建新用户时的默认赋值字段,修改谷歌策略中的回调代码如下:
User.findOrCreate( // 仅用唯一标识做查询条件 { googleId: profile.id }, // 新用户创建时的默认字段值 { username: profile.displayName, profileImage: profile.photos[0].value, myCollection: catalogDb, games: {} }, function(err, user) { return cb(err, user); } );
如果需要每次登录都更新用户的昵称、头像等最新信息,可以在回调中补充更新逻辑:
User.findOrCreate( { googleId: profile.id }, { username: profile.displayName, profileImage: profile.photos[0].value, myCollection: catalogDb, games: {} }, function(err, user, created) { // 非新创建的用户,每次登录更新最新的昵称和头像 if (!created) { user.username = profile.displayName; user.profileImage = profile.photos[0].value; user.save().then(updatedUser => cb(err, updatedUser)); return; } return cb(err, user); } );
方案2:移除不需要的依赖
如果你的应用只使用谷歌OAuth登录,不需要本地用户名密码登录功能,可以直接移除passport-local-mongoose插件相关代码,就不会自动生成username的唯一索引,从根源避免这个问题。
方案3:关闭username唯一索引校验
如果确实需要保留passport-local-mongoose的功能,可在初始化插件时关闭唯一索引校验:
userSchema.plugin(passportLocalMongoose, { usernameUnique: false });
注意:修改配置后需要手动删除MongoDB中users集合已存在的
username_1唯一索引,否则配置不会生效。
内容的提问来源于stack exchange,提问作者Artemis
相关产品推荐
相关产品推荐

