Mongoose FindOne返回查询对象而非集合文档问题求助
问题:Mongoose findOne() 返回查询对象而非文档,添加await触发"query already executed"错误
我是NodeJS新手,正在用Mongoose完成大学项目。调用model.findOne()时返回的是查询对象和模型元数据,不是目标文档;在userModel.findOne()前加await会触发Mongoose的"query already executed"错误,试过回调也没解决问题。以下是相关代码与输出:
用户Schema
var mongoose = require('mongoose'); //Define Collection Schema const userSchema = new mongoose.Schema({ emailId:{ type: String, required: true }, userName:{ type: String, required: true }, password:{ type: String, required: true }, role:{ type: String, required: true, default: "user" }, playlist:[{ type: String, type: mongoose.Schema.Types.ObjectId, ref: "vidmodel" }], likes:[{ type: String, type: mongoose.Schema.Types.ObjectId, ref: "vidmodel" }], dislikes:[{ type: String, type: mongoose.Schema.Types.ObjectId, ref: "vidmodel" }] }) userSchema.pre('save', function(next) { this.emailId=this.emailId.toLowerCase(); next(); }) module.exports = mongoose.model('usermodel', userSchema)
函数代码
const userModel = require('./models/userModel') app.post('/user/signup', upload.single(''), async(req,res)=>{ try{ const formData = req.body const email = formData.email const password = formData.password existingUser=userModel.findOne({emailId:email}, function(err, user){ if(user){ console.log("output of findOne",user) } if(err){ console.log(err) } }) if(existingUser){ console.log(existingUser) } } catch(err){ console.log(err) } })
输出内容
Query { _mongooseOptions: {}, _transforms: [], _hooks: Kareem { _pres: Map(0) {}, _posts: Map(0) {} }, _executionStack: null, mongooseCollection: Collection { collection: Collection { s: [Object] }, Promise: [Function: Promise], modelName: 'usermodel', _closed: false, opts: { autoIndex: true, autoCreate: true, schemaUserProvidedOptions: {}, capped: false, Promise: [Function: Promise], '$wasForceClosed': undefined }, name: 'usermodels', collectionName: 'usermodels', conn: NativeConnection { base: [Mongoose], collections: [Object], models: [Object], config: {}, replica: false, options: null, otherDbs: [], relatedDbs: {}, states: [Object: null prototype], _readyState: 1, _closeCalled: undefined, _hasOpened: true, plugins: [], id: 0, _queue: [], _listening: false, _connectionString: 'mongodb://localhost/streambytes-dev', _connectionOptions: [Object], client: [MongoClient], '$initialConnection': [Promise], db: [Db], host: 'localhost', port: 27017, name: 'streambytes-dev' }, queue: [], buffer: false, emitter: EventEmitter { _events: [Object: null prototype] {}, _eventsCount: 0, _maxListeners: undefined, [Symbol(kCapture)]: false } }, model: Model { usermodel }, schema: Schema { obj: { emailId: [Object], userName: [Object], password: [Object], role: [Object], playlist: [Array], likes: [Array], dislikes: [Array] }, paths: { emailId: [SchemaString], userName: [SchemaString], password: [SchemaString], role: [SchemaString], playlist: [SchemaArray], likes: [SchemaArray], dislikes: [SchemaArray], _id: [ObjectId], __v: [SchemaNumber] }, aliases: {}, subpaths: { 'playlist.$': [ObjectId], 'likes.$': [ObjectId], 'dislikes.$': [ObjectId] }, virtuals: { id: [VirtualType] }, singleNestedPaths: {}, nested: {}, inherits: {}, callQueue: [], _indexes: [], methods: {}, methodOptions: {}, statics: {}, tree: { emailId: [Object], userName: [Object], password: [Object], role: [Object], playlist: [Array], likes: [Array], dislikes: [Array], _id: [Object], __v: [Function: Number], id: [VirtualType] }, query: {}, childSchemas: [], plugins: [ [Object], [Object], [Object], [Object], [Object] ], '$id': 3, mapPaths: [], s: { hooks: [Kareem] }, _userProvidedOptions: {}, options: { typeKey: 'type', id: true, _id: true, validateBeforeSave: true, read: null, shardKey: null, discriminatorKey: '__t', autoIndex: null, minimize: true, optimisticConcurrency: false, versionKey: '__v', capped: false, bufferCommands: true, strictQuery: true, strict: true, pluralization: true }, '$globalPluginsApplied': true }, op: 'findOne', options: {}, _conditions: { emailId: 'JCD@unatco.com' }, _fields: undefined, _update: undefined, _path: undefined, _distinct: undefined, _collection: NodeCollection { collection: Collection { collection: [Collection], Promise: [Function: Promise], modelName: 'usermodel', _closed: false, opts: [Object], name: 'usermodels', collectionName: 'usermodels', conn: [NativeConnection], queue: [], buffer: false, emitter: [EventEmitter] }, collectionName: 'usermodels' }, _traceFunction: undefined, '$useProjection': true }
解决方案
问题根源
你同时混用了回调函数和异步变量赋值两种方式:
userModel.findOne()传入回调时,会立即执行查询,但返回值是Query对象(不是查询结果),所以existingUser拿到的是Query实例,不是文档。- 如果你之后再给这个Query加
await,就会触发"query already executed"——因为查询已经通过回调执行过了。
正确写法(二选一)
方式1:只用async/await(推荐)
去掉回调,用await直接获取查询结果,代码更简洁易读:
const userModel = require('./models/userModel') app.post('/user/signup', upload.single(''), async(req,res)=>{ try{ const { email, password } = req.body; const existingUser = await userModel.findOne({emailId: email}); if(existingUser){ console.log("找到用户:", existingUser); res.status(400).send("用户已存在"); } else { // 处理用户不存在的逻辑,比如创建新用户 } } catch(err){ console.error(err); res.status(500).send("服务器错误"); } })
方式2:只用回调函数
如果坚持用回调,不要把findOne的返回值赋值给变量,所有逻辑都在回调里处理:
const userModel = require('./models/userModel') app.post('/user/signup', upload.single(''), (req,res)=>{ const { email, password } = req.body; userModel.findOne({emailId: email}, function(err, user){ if(err){ console.error(err); return res.status(500).send("服务器错误"); } if(user){ console.log("找到用户:", user); return res.status(400).send("用户已存在"); } // 处理创建新用户的逻辑 }) })
额外注意点
- 你的Schema里数组字段(playlist/likes/dislikes)重复定义了
type: String和type: ObjectId,后面的会覆盖前面的,建议删掉多余的type: String:
playlist:[{ type: mongoose.Schema.Types.ObjectId, ref: "vidmodel" }], // likes和dislikes同理修改
- 记得给
existingUser加上const或let声明,避免全局变量污染。
内容的提问来源于stack exchange,提问作者Redgrave
相关产品推荐
相关产品推荐

