modifiers can not be used anymore.
Following method works as of August 2020.
Using explain db command.
More on that https://docs.mongodb.com/manual/reference/command/explain/#dbcmd.explain
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
@Service
public class MongodbExplain {
@Autowired
private MongoTemplate mongoTemplate;
public String explainQuery(Query query, String collectionName) {
Document explainDocument = new Document();
explainDocument.put("find", collectionName);
explainDocument.put("filter", query.getQueryObject());
Document command = new Document();
command.put("explain", explainDocument);
Document explainResult = mongoTemplate.getDb().runCommand(command);
return explainResult.toJson();
}
@PostConstruct
public void postConstrucut() {
Query query = new Query(Criteria.where("name").is("enes"));
String explainResult = explainQuery(query, "person");
System.out.println(explainResult);
}
}
Guys at MongoDB did some breaking changes to java driver.
Following method works as of March 2019.
modifiers method seems to be deprecated as well. I'll update this page again if they break it too.
package com.example.demo;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
@Service
public class MongodbExplain {
@Autowired
private MongoTemplate mongoTemplate;
public String explainQuery(Query query, String collectionName) {
MongoCollection<Document> collection = mongoTemplate.getCollection(collectionName);
FindIterable<Document> result = collection.find(query.getQueryObject()).modifiers(new Document("$explain", true));
return result.first().toJson();
}
@PostConstruct
public void postConstrucut() {
Query query = new Query(Criteria.where("name").is("enes"));
String explainResult = explainQuery(query, "person");
System.out.println(explainResult);
}
}
Sometimes you want to see if your queries are using indexes or not when using MongoDB with the help of Spring.
With 3 lines of code you can check if an index is being used.
DBCollection collection = mongoTemplate.getCollection(collectionName);
DBCursor cursor = collection.find(query.getQueryObject());
System.out.println(cursor.explain());
Here is a working example.
package enesaltinkayacom.util;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import enesaltinkayacom.post.Post;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class Explain {
@Autowired
private MongoTemplate mongoTemplate;
public List<Post> someJob(String title) {
Criteria criteria = new Criteria();
criteria.andOperator(Criteria.where("title").is(title),
Criteria.where("deleted").is(false));
Query query = new Query(criteria);
query.limit(10);
query.skip(10);
query.with(new Sort(Sort.Direction.DESC, "date"));
explainQuery(query, "post");
return mongoTemplate.find(query, Post.class);
}
public void explainQuery(Query query, String collectionName) {
DBCollection collection = mongoTemplate.getCollection(collectionName);
DBCursor cursor = collection.find(query.getQueryObject());
System.out.println(cursor.explain());
}
}
Output is rather long.
I copy and paste such long json outputs to http://jsoneditoronline.org/
You can see that queryPlanner -> winningPlan -> inputStage -> stage is IXSCAN.
Which means our query is indeed using an index.
Stage can be one of the four,
More on that mongodb.com explain-results
{
"queryPlanner": {
"plannerVersion": 1,
"namespace": "enesaltinkaya.post",
"indexFilterSet": false,
"parsedQuery": {
"$and": [
{
"deleted": {
"$eq": false
}
},
{
"title": {
"$eq": "Test"
}
}
]
},
"winningPlan": {
"stage": "FETCH",
"filter": {
"deleted": {
"$eq": false
}
},
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
"title": 1
},
"indexName": "title",
"isMultiKey": false,
"multiKeyPaths": {
"title": []
},
"isUnique": false,
"isSparse": false,
"isPartial": false,
"indexVersion": 2,
"direction": "forward",
"indexBounds": {
"title": [
"[\"Test\", \"Test\"]"
]
}
}
},
"rejectedPlans": []
},
"executionStats": {
"executionSuccess": true,
"nReturned": 0,
"executionTimeMillis": 0,
"totalKeysExamined": 0,
"totalDocsExamined": 0,
"executionStages": {
"stage": "FETCH",
"filter": {
"deleted": {
"$eq": false
}
},
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 1,
"advanced": 0,
"needTime": 0,
"needYield": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"docsExamined": 0,
"alreadyHasObj": 0,
"inputStage": {
**"stage": "IXSCAN",**
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 1,
"advanced": 0,
"needTime": 0,
"needYield": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"keyPattern": {
"title": 1
},
"indexName": "title",
"isMultiKey": false,
"multiKeyPaths": {
"title": []
},
"isUnique": false,
"isSparse": false,
"isPartial": false,
"indexVersion": 2,
"direction": "forward",
"indexBounds": {
"title": [
"[\"Test\", \"Test\"]"
]
},
"keysExamined": 0,
"seeks": 1,
"dupsTested": 0,
"dupsDropped": 0,
"seenInvalidated": 0
}
},
"allPlansExecution": []
},
"serverInfo": {
"host": "arch",
"port": 27017,
"version": "3.4.7",
"gitVersion": "cf38c1b8a0a8dca4a11737581beafef4fe120bcd"
},
"ok": 1
}