13

Is there a way to run .explain() or equivalent on Linq queries? I would want to know

  • The text of the actual JSON query
  • The output of .explain() (indexes used, etc)
  • It would also be nice to have the execution time of the query
bruce
  • 15
  • 3
kelloti
  • 8,705
  • 5
  • 46
  • 82

4 Answers4

12

You can get the Json easily enough if you have a query wrapper;

var qLinq = Query<T>.Where(x => x.name=="jim");
Console.WriteLine(qLinq.ToJson());

There's also an Explain() method on MongoCursor, so you could do this;

var exp = Collection.FindAs<T>(qLinq).Explain()
Console.WriteLine(exp.ToJson());

So if you want the time taken, "millis" is in there;

var msTaken = exp.First(x => x.Name == "millis").Value.AsInt32;

If you have an IQueryable, try something like this;

void Do(MongoCollection col, IQueryable iq)
{
        // Json Mongo Query
        var imq = (iq as MongoQueryable<Blob>).GetMongoQuery();
        Console.WriteLine(imq.ToString());

        // you could also just do;
        // var cursor = col.FindAs(typeof(Blob), imq);
        var cursor = MongoCursor.Create(typeof(Blob), col, imq, ReadPreference.Nearest);
        var explainDoc = cursor.Explain();

        Console.WriteLine(explainDoc);
    }//Do()
Community
  • 1
  • 1
cirrus
  • 5,624
  • 8
  • 44
  • 62
  • Thanks. Most of our queries are from `IQueryable` objects. Maybe the better question is how to turn an `IQueryable` into an `IMongoQuery`? – kelloti Nov 07 '12 at 00:06
  • That's not so easy to go in that direction, but you can do it - see updated answer. The other approach is to put a Repository over the Mongo Linq layer so that you can work with Query<> objects directly, do your logging then return IQueryable rather than try and convert IQueryable to Query<> – cirrus Nov 07 '12 at 12:17
  • thanks for the help. Your solution doesn't actually compile though. See my updates for what actually works for me (note how I have to rip deep into the `Expression` to get the `where` clause). – kelloti Nov 07 '12 at 22:41
  • Sorry, I was writing blind. In any case, I think it's a lot easier than this. The Expression is probably a red-herring we really want a MongoCursor, see above. – cirrus Nov 08 '12 at 12:28
  • 1
    The latest version of the Driver has an "Explain" extension method for IQueryable. – drogon Feb 27 '13 at 23:57
  • @cirrus It's probably time to just delete all that strike-through text from your answer. – JohnnyHK Jul 25 '14 at 17:22
5

If you want this functionality in a library, I just created a GitHub project entitled

MongoDB query helper for .NET

https://github.com/mikeckennedy/mongodb-query-helper-for-dotnet

It will:

  • Explain a LINQ query as a strongly typed object (does it use an index for example)
  • Convert a LINQ query to the JavaScript code run in MongoDB

Check it out and contribute if you find it interesting.

Michael Kennedy
  • 3,202
  • 2
  • 25
  • 34
2

Yes, there is. It shows everything .explain does and has a boolean for verbosity (it includes the time it took to execute):

var database = new MongoClient().GetServer().GetDatabase("db");
var collection = database.GetCollection<Hamster>("Hamsters");

var explanation = collection.AsQueryable().Where(hamster => hamster.Name == "bar").Explain(true);
Console.WriteLine(explanation);

It doesn't show the query though. Here's an extension method for that:

public static string GetMongoQuery<TItem>(this IQueryable<TItem> query)
{
    var mongoQuery = query as MongoQueryable<TItem>;
    return mongoQuery == null ? null : mongoQuery.GetMongoQuery().ToString();
}

Usage:

var query = collection.AsQueryable().Where(hamster => hamster.Name == "bar").GetMongoQuery();
Console.WriteLine(query);
i3arnon
  • 113,022
  • 33
  • 324
  • 344
1

In mongodb 3 C# I used following:

var users = Mongo.db.GetCollection<User>("Users");
var r = users(m => m._id == yourIdHere)
    .Project(m => new { m._id, m.UserName, m.FirstName, m.LastName })
    .Limit(1);

Console.WriteLine(r.ToString());

Result:

find({ "_id" : ObjectId("56030e87ca42192008ed0955") }, { "_id" : 1, "UserName" : 1, "FirstName" : 1, "LastName" : 1 }).limit(1) 
user1195202
  • 1,423
  • 1
  • 16
  • 20