gknauth gknauth - 2 months ago 6
Scala Question

Does MongoDB Scala driver have any equivalent to the explain() function in the JavaScript interface?

Does MongoDB Scala driver have any equivalent to the

explain()
function in the JavaScript interface?

I'm wondering what the MongoDB Scala driver does with a query like this:

collection.find(
and(geoWithinBox("geometry", bbox.swLon, bbox.swLat, bbox.neLon, bbox.neLat),
equal("properties.foo", "abc"),
exists("properties.bar")))
.limit(100)


MongoDB does not seem to be using the geospatial index I created and I'm trying to figure out why. Rather, it seems to be scanning every document. At least that's what I noticed when I tried
explain
with this JS query in MongoShell:

{$and: [{"geometry": {$geoWithin: {$box: [ [-78,40],[-76,41] ] }}},
{$and: [{"properties.foo": {$eq: "abc"}},
{"properties.bar": {$exists: 1}}
]
}
]
}


(I didn't have nested-
and
s in the first version of the JS immediately above. I was just trying different things to see if they triggered use of the geospatial index.)

Answer

This answer is based on current MongoDB Scala driver v1.1.0 and current MongoDB v3.2.

Currently there is no cursor explain() function via the Scala driver. This is because explain has been determined to be not a normal use-case for a driver. I would recommend to use the Mongo Shell for debugging query index usages. See MongoDB driver spec for more info.

However you can still use runCommand to get explain output. For example of $geoWithin query in Mongo Shell :

db.collection.find({
    "geometries":{
        $geoWithin:{
            $box:[[-78,40], [-76, 41]]
        }
    }
}).explain()

You can do the same using command in Scala like below:

val command = Document("explain" -> Document("find"->"collection", 
                        "filter"->Document("geometries"->Document(
                                "$geoWithin"->Document(
                                     "$box"->Seq(Seq(-78, 40), Seq(-76, 41))
                                  )
                            )
                        )
                    )
               )
val observable = db.runCommand(command).printHeadResult()

Or for aggregation queries

  db.runCommand(
    Document(
      "aggregate" -> "collection",
      "pipeline" -> List[Document]( ... ),
      "explain" -> true
    )
  )

Worth mentioning that only 2d geospatial index supports $box operator. Make sure that you have the right index for field geometries.

Also, by default queries are constructed implicitly with AND, so you don't have to specify $and explicitly. Your example can be shorten to :

db.collection.find({"geometry": {$geoWithin: {$box: [[-78,40],[-76,41]] }},
                    "properties.foo" : "abc", 
                    "properties.bar": {$exists:true}
                   })
Comments