You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MERN+TypeScript实现Google登录时遇Mongoose Schema配置错误

问题排查:TypeScript MERN项目中Passport Google登录的Schema配置错误

配置Passport实现Google登录时出现以下错误:

TypeError: Invalid schema configuration: `false` is not a valid type at path `select`

以下是相关代码及依赖版本,附问题修复方案:

User Schema代码

interface userInterface{
    name : string,
    userHandle : string,
    profilePic? : string,
    following : Schema.Types.ObjectId[],
    followers :  Schema.Types.ObjectId[],
    auth : {
        signInType :string,
        sessionInfo : {
            password : string
        },
        googleInfo : {
            googleId : string,
        }
    }   
}

const userSchema = new Schema<userInterface>({
    name : {
        type : String,
        required : [true, 'Name is required.'],
        maxlength : [50 , 'Name must not exceed 50 charecters.']
    },
    userHandle : {
        type : String,
        required : [true , 'User handle is required.'],
        unique : [true, 'Please enter a unique user handle.']
    },
    profilePic : {
        type : String,
    },
    following : {
        type:  [Schema.Types.ObjectId], 
        ref : 'User'
    },
    followers : {
        type :  [Schema.Types.ObjectId], 
        ref : 'User'
    },
    auth : {
        select: false,
        signInType : {
            type : String,
            enum : ["Google" , "Session"]
        },
        sessionInfo : {
            password : {
                type : String,
                required : [function(this : any){
                    return this.auth.signInType === "Session"; 
                } , "Please enter a password."],
            }
        },
        googleInfo : {
            googleId : {
                type : String,
                required : [function(this : any){
                    return this.auth.signInType === "Google";
                }, "Please enter a google id."]
            }
        },
    },
}, {timestamps : true})

export default model<userInterface>('User' , userSchema);

Passport配置代码

import passport from "passport";
import passportGoogle from "passport-google-oauth2";
import User from "../model/UserSchema";
import {userHandleGenerater} from "../utils/utils";
const GoogleStrategy = passportGoogle.Strategy;

passport.use(
  new GoogleStrategy(
    {
      clientID: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
      callbackURL: `${process.env.FRONTEND_URI as string}/home`,
    },
    async (accessToken , refreshToken, profile , done) => {
        try{
            let user = await User.findOne({"googleInfo.googleId" : profile.id});
            if(!user){
                let userHandle = "";
                let found = true;
      
                while (found) {
                  userHandle = userHandleGenerater(profile.name.givenName);
                  let existingUser = await User.findOne({ userHandle });
                  if (existingUser) {
                    found = true; 
                  } else {
                    found = false; 
                  }
                }

                const newUser = {
                    name : profile.displayName, 
                    userHandle : userHandle,
                    auth : {
                        signInType : "Google",
                        googleInfo : {
                            googleId : profile.id
                        },
                    }
                }

                user = await User.create(newUser);
            }   
            return done(null , user);
        }catch(e){
            return done(e , null);
        }
    }
  )
);


passport.serializeUser((user : any , done) => {
    done(null , user._id);
});

passport.deserializeUser(async (id , done) => {
    try {
        const user = await User.findById(id);
        return done(null , user);
    }catch(e){
        return done(e, null);
    }
});

项目依赖包版本

"dependencies": {
    "@types/express-session": "^1.18.1",
    "@types/node-cron": "^3.0.11",
    "@types/passport-google-oauth2": "^0.1.10",
    "backend": "file:",
    "cors": "^2.8.5",
    "express": "^4.21.2",
    "express-session": "^1.18.1",
    "mongoose": "^8.9.5",
    "node-cron": "^3.0.3",
    "passport": "^0.7.0",
    "passport-google-oauth2": "^0.2.0",
    "passport-google-oidc": "^0.1.0"
  },
  "devDependencies": {
    "@types/cors": "^2.8.17",
    "@types/express": "^5.0.0",
    "@types/node": "^22.10.7",
    "@types/passport": "^1.0.17",
    "dotenv": "^16.4.7",
    "nodemon": "^3.1.9",
    "rimraf": "^6.0.1",
    "ts-node": "^10.9.2",
    "typescript": "^5.7.3"
  }

问题根源及修复方案

  1. Schema配置错误
    你在auth嵌套字段中直接将select: false写在对象内部,Mongoose会把select识别为普通字段,而false不是合法的字段类型,因此报错。正确的做法是将select作为auth字段的选项,与type同级定义。

    修复后的auth字段定义:

    auth : {
      type: {
        signInType : {
          type : String,
          enum : ["Google" , "Session"]
        },
        sessionInfo : {
          password : {
            type : String,
            required : [function(this : any){
              return this.auth.signInType === "Session"; 
            } , "Please enter a password."],
          }
        },
        googleInfo : {
          googleId : {
            type : String,
            required : [function(this : any){
              return this.auth.signInType === "Google";
            }, "Please enter a google id."]
          }
        },
      },
      select: false, // 将select作为auth字段的选项
    },
    
  2. Passport查询路径错误
    原代码中查询Google用户的条件路径错误,应为auth.googleInfo.googleId而非googleInfo.googleId,同时因为auth字段默认不返回,需要显式指定查询该字段:

    let user = await User.findOne({"auth.googleInfo.googleId": profile.id}).select("+auth.googleInfo.googleId");
    

内容的提问来源于stack exchange,提问作者abhinav550

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 18:15:54