Mongoose调用Collection.find报is synchronous错误,findOne运行正常
问题现象
仅在调用集合的find方法时触发错误,findOne方法可正常运行,触发的报错信息如下:
throw new Error('Collection method ' + i + ' is synchronous');
代码逻辑为封装MongoDB连接逻辑后,在异步函数中通过await调用集合的find方法,查询价格不低于200的商品数据并仅返回price字段,运行时直接抛出上述同步方法错误。
涉及代码
index.js
const mongoose = require("mongoose"); const { database } = require("./server"); database(); let db = mongoose.connection; let Products = db.collection("Products"); async function FindProd() { let findProd = await Products.find( { price: { $gte: 200 } }, { projection: { price: 1, _id: 0 } } ); console.log(findProd); } FindProd();
server.js
const mongoose = require("mongoose"); let database = function () { mongoose.connect("mongodb://127.0.0.1:27017/mydb", (err, res) => { if (res) { console.log("connection successfull"); } else { console.log("error:", err); } }); }; module.exports = { database };
问题成因
- 代码调用
database()发起数据库连接后,没有等待连接建立完成,就同步执行db.collection("Products")获取集合实例。此时数据库连接还处于待完成状态,拿到的是Mongoose提供的未就绪Collection代理对象,并非原生MongoDB驱动的可用Collection实例。 - Mongoose对未就绪状态的集合方法做了占位处理:
findOne这类直接返回文档结果的方法做了隐式等待兼容,会在连接就绪后自动执行;但find方法返回值是游标类型,占位逻辑为直接同步抛出错误,不会等待连接就绪,这就是报错的直接来源。 - 代码还存在额外逻辑问题:即使连接状态正常,直接
await Products.find()也无法拿到预期的查询结果——原生MongoDB驱动的find方法返回的是查询游标,不是结果Promise,需要调用游标上的toArray()等方法才能获取实际文档数据。
解决方法
- 改造数据库连接逻辑,让连接方法返回Promise,所有数据库操作必须等待连接成功后再执行,禁止在连接发起阶段同步获取集合实例。
- 修正
find方法的调用逻辑,拿到查询游标后调用toArray()方法获取最终的查询结果数组。 - 若不想手动管理连接状态,可直接使用Mongoose官方推荐的Schema/Model体系操作集合,Mongoose会自动处理连接等待、方法兼容问题。
修正后代码
server.js
const mongoose = require("mongoose"); let database = function () { return new Promise((resolve, reject) => { mongoose.connect("mongodb://127.0.0.1:27017/mydb", (err, res) => { if (res) { console.log("connection successfull"); resolve(res); } else { console.log("error:", err); reject(err); } }); }) }; module.exports = { database };
index.js
const mongoose = require("mongoose"); const { database } = require("./server"); async function run() { // 等待数据库连接完成 await database(); const db = mongoose.connection; const Products = db.collection("Products"); // find返回游标,调用toArray获取结果数组 const findProd = await Products.find( { price: { $gte: 200 } }, { projection: { price: 1, _id: 0 } } ).toArray(); console.log(findProd); } run();
内容的提问来源于stack exchange,提问作者Sibi
相关产品推荐
相关产品推荐

