Description
Prerequisites
- I have written a descriptive issue title
- I have searched existing issues to ensure the performance issue has not already been reported
Last performant version
"^6.8.1"
Slowed down in version
"^8.9.4"
Node.js version
18.x
🦥 Performance issue
I'm facing a severe performance issue with Mongoose v8.9.5. Despite the MongoDB explain output showing lightning-fast query execution on the database, Mongoose is inexplicably taking an unreasonably long time to return results.
For example, the following simple query takes around 700 ms, however, when using the native mongodb driver the result is returned in 60ms.
console.time("mongoose");
await Business.findById(new ObjectId("673e24037abe20cc29e0225b")).lean();
console.timeEnd("mongoose");
Output: 695.934ms
console.time("Native MongoDB Driver");
await db
.collection("businesses")
.findOne({ _id: new ObjectId("673e24037abe20cc29e0225b") });
console.timeEnd("Native MongoDB Driver");
Output: 64.584ms
I suspect this could be related to how Mongoose processes the query or interacts with MongoDB in this version. The problem persists despite having the appropriate indexes in place and minimal query execution time reported by MongoDB.
Environment:
Node.js Version: v18.20.4
Mongoose Version: v8.9.5
MongoDB Driver Version: v6.12.0 (mongoose dependency)
MongoDB Server Version: 8.0.4 (Atlas Cluster)
OS: Amazon Linux 2 (AWS Lambda)
This occurred only after I updated the mongoose version from v6.8.1 to v8.9.5, and the MongoDB Server Version from 6.0.0 to 8.0.4
Could this be a bug in Mongoose v8.9.5? What else can I try to find the cause of this slowdown?
What I’ve Tried For Each Query:
- Verified that MongoDB itself is not at fault (query execution is fast per explain()).
- Ensured proper indexing on the collection fields.
- Added mongoose.set('debug', true) to confirm the query being executed is correct.
- Cleared npm cache and reinstalled dependencies to rule out dependency corruption.
- Checked with MongoDB support to double check it doesn't show up as a slow operation.
Could this be a regression or specific issue with Mongoose v8.9.5? Is there any additional debugging you recommend to pinpoint the cause of this delay?
Steps to Reproduce
1. Define the schema and create a million mock documents:
const TransactionSchema = new mongoose.Schema({
businessId: { type: mongoose.Schema.Types.ObjectId, required: true },
acquirerTransactionId: { type: String, index: true },
partnerReferenceId: { type: String, index: true },
tempUniqueId: { type: String, index: true },
transactionTime: { type: Date, index: true },
});
const Transaction = mongoose.model("Transaction", TransactionSchema);
Use the following code to connect to MongoDB and log the Mongoose and MongoDB driver versions:*
import mongoose from "mongoose";
mongoose.Promise = global.Promise;
let isConnected;
export const connectToDatabase = () => {
if (isConnected) {
console.log("DB connection was previously established");
return Promise.resolve();
}
console.log("Establishing a new DB connection...");
console.log(`Mongoose version: ${mongoose?.version}`);
const DB_URL = "mongodb+srv://<username>:<password>@<cluster>.mongodb.net/dbname";
mongoose.set("strictQuery", true);
return mongoose
.connect(DB_URL, { maxIdleTimeMS: 60000 })
.then((db) => {
isConnected = db.connections[0].readyState;
try {
const connection = mongoose.connection;
const driverInfo = connection?.client?.s?.options?.metadata;
if (driverInfo) {
console.log(`MongoDB Driver Info:`, driverInfo);
} else {
console.log("Driver info is not accessible.");
}
} catch (error) {
console.error("Error accessing MongoDB driver info:", error);
}
})
.catch((err) => {
console.error("Connection error:", err);
});
};
connectToDatabase();
3. Execute the query:
const result = await Transaction.findOne({
$or: [
{ acquirerTransactionId: "502109000037" },
{ partnerReferenceId: "502109000037" },
{ tempUniqueId: "502109000037" },
],
businessId: "673e24037abe20cc29e0225b",
});
console.log("Query result:", result);
4. Observe the following:
Always takes more than around 1 second.
MongoDB query execution time (based on explain) is ~1 millisecond.
5. Run the explain() on the query directly on MongoDB, and see that the winning plan looks optimal. Here’s the relevant snippet of what I got:
{
"queryPlanner": {
"winningPlan": {
"stage": "FETCH",
"filter": { "businessId": { "$eq": "673e24037abe20cc29e0225b" } },
"inputStage": {
"stage": "OR",
"inputStages": [
{
"stage": "IXSCAN",
"keyPattern": { "acquirerTransactionId": 1 },
"indexBounds": { "acquirerTransactionId": [ "[\"502109000037\", \"502109000037\"]" ] }
},
{
"stage": "IXSCAN",
"keyPattern": { "tempUniqueId": 1 },
"indexBounds": { "tempUniqueId": [ "[\"502109000037\", \"502109000037\"]" ] }
},
{
"stage": "IXSCAN",
"keyPattern": { "partnerReferenceId": 1 },
"indexBounds": { "partnerReferenceId": [ "[\"502109000037\", \"502109000037\"]" ] }
}
]
}
}
},
"executionStats": {
"executionTimeMillis": 1,
"totalKeysExamined": 1,
"totalDocsExamined": 1
}
}
Expected Behavior
The query should return results in a reasonable time frame (similar to the MongoDB execution time, with minimal additional overhead).