I'm looking for some advice on how to improve the performance of my query.
I have this user model in mongoose and I'm indexing interested_cities.
const firebaseToken = new Schema({
type: {
type: String,
default: "android",
required: true,
trim: true,
},
device_id: {
type: String,
required: true,
trim: true,
},
fcm_token: {
type: String,
required: true,
trim: true,
},
});
const userSchema = new Schema({
name: {
type: String,
required: true,
trim: true,
},
interested_cities: {
type: [{
type: String,
trim: true,
lowercase: true,
unique: true
}],
required: false,
default: [],
},
push_notification_tokens_firebase: {
type: [firebaseToken],
required: false,
default: [],
},
});
userSchema.index({
interested_cities: 1
});
What I'm looking for is to query the users who have 'A' or 'B' in their array of interested_cities.
I'm querying something like this. I only need the firebase fcm_token from the query.
const involvedUsers = await User.find(
{
$or: [
{ interested_cities: { $in: ['A', 'B'] } },
{ phone_number: { $in: adminPhoneNumbersList } },
],
},
{
_id: 1,
"push_notification_tokens_firebase.fcm_token": 1,
}
);
Currently, the query is taking 20 sec for 14k documents, which needs improvements. Any pointers would be appreciated.
Explain:
{
"explainVersion": "1",
"queryPlanner": {
"namespace": "production.users",
"indexFilterSet": false,
"parsedQuery": {
"interested_cities": {
"$in": [
"A",
"B"
]
}
},
"maxIndexedOrSolutionsReached": false,
"maxIndexedAndSolutionsReached": false,
"maxScansToExplodeReached": false,
"winningPlan": {
"stage": "PROJECTION_DEFAULT",
"transformBy": {
"_id": 1,
"push_notification_tokens_firebase.fcm_token": 1
},
"inputStage": {
"stage": "FETCH",
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
"interested_cities": 1
},
"indexName": "interested_cities_1",
"isMultiKey": true,
"multiKeyPaths": {
"interested_cities": [
"interested_cities"
]
},
"isUnique": false,
"isSparse": false,
"isPartial": false,
"indexVersion": 2,
"direction": "forward",
"indexBounds": {
"interested_cities": [
"[\"A\", \"A\"]",
"[\"B\", \"B\"]"
]
}
}
}
},
"rejectedPlans": []
}
"executionStats": {
"executionSuccess": true,
"nReturned": 6497,
"executionTimeMillis": 48,
"totalKeysExamined": 0,
"totalDocsExamined": 14827,
"executionStages": {
"stage": "SUBPLAN",
"nReturned": 6497,
"executionTimeMillisEstimate": 46,
"works": 14829,
"advanced": 6497,
"needTime": 8331,
"needYield": 0,
"saveState": 14,
"restoreState": 14,
"isEOF": 1,
"inputStage": {
"stage": "PROJECTION_DEFAULT",
"nReturned": 6497,
"executionTimeMillisEstimate": 46,
"works": 14829,
"advanced": 6497,
"needTime": 8331,
"needYield": 0,
"saveState": 14,
"restoreState": 14,
"isEOF": 1,
"transformBy": {
"_id": 1,
"push_notification_tokens_firebase.fcm_token": 1
},
"inputStage": {
"stage": "COLLSCAN",
"filter": {
"$or": [
{
"interested_cities": {
"$in": [
"A",
"B"
]
}
},
{
"phone_number": {
"$in": [
"phone numbers",
"phone number"
]
}
}
]
},
"nReturned": 6497,
"executionTimeMillisEstimate": 41,
"works": 14829,
"advanced": 6497,
"needTime": 8331,
"needYield": 0,
"saveState": 14,
"restoreState": 14,
"isEOF": 1,
"direction": "forward",
"docsExamined": 14827
}
}
},
"allPlansExecution": []
}