3

I have the following classes:

public class Company
{
   [BsonId]
   public string dealerId = null;

   public List<Dealer> dealers = new List<Dealer>();
}

public class Dealer
{        
   public string dId = null;          
   public int dIndex = -1;

   public List<AutoStore> stores = new List<AutoStore>();
}

public class AutoStore
{
   public string type = null; 
   public  Dictionary<string, object> data = new Dictionary<string, object>();
}

I am able to store the Company class objects in Mongo with Insert(). The problem is when I search for a document and try to use LINQ on the List<> items. I constantly get an exception .

var query =  collection.AsQueryable<Company>()
                 .Where(cpy =>
                     cpy.dealers.Where(dlr => 
                         dlr.stores.Count == 1).Count() > 0) ;

Running this code I get:

System.NotSupportedException: Unable to determine the serialization information for the expression: Enumerable.Count

I just started using Mongo today, but I thought the LINQ support was more mature. Can anyone tell me if I can do a nested array query like I've done with C# andLINQ ?

As soon as I remove the Where() on any of the List<> , that exception isn't thrown

4
  • Any reason why you use Count twice? Try to use cpy.Dealers.Any(dlr => dlr.stores.Count ==1) if all you want to do is see if the dealer has any stores (that's what I judge from the code) Commented Jan 31, 2013 at 9:26
  • 2
    In general in LINQ, instead of saying .Count() > 0 or .Count(lambdaFunc) > 0, always use .Any() respectively .Any(lambdaFunc). The reason is that to determine the count, it will have to iterate the entire source to the end, while to determine if there is Any, it only has to iterate until it finds the first element! (And Any is even easier to type than Count and > 0.) Commented Jan 31, 2013 at 9:33
  • And an extension of this comment. Instead of saying .Count() == n for some positive integer n, it might perform better to say .Take(n + 1).Count() == n. And so on. Commented Jan 31, 2013 at 10:02
  • Jodrell: collection is an object returned from database.GetCollection<> ; Jeppe Stig: Thanks for the tip, I will use Any() from now on; LukeHennerly: I tried it without using Count() but I still got an exception on Where(). I dont have to use Count, but I was just trying a simple query to test against my inserted data. Commented Jan 31, 2013 at 17:22

2 Answers 2

4

Going by your exception the problem area is within where you are doing Where statements.

As I said in my comment. Try to do:

var v = collection.AsQueryable<Company>().Where(cpy => cpy.Dealers.Any(dlr => dlr.Stores.Count == 1));

You are currently doing something like:

var dealers = collection.AsQueryable<Company>().Select(cpy => cpy.Dealers);
var dealersWithStores = dealers.Where(dealer => dealer.Stores.Count == 1);

You are then checking if there are any dealers with stores by calling count and checking if that is more than 0 to get your bool in the where. All of this is the same as calling IEnumerable.Any(). See if this works? :)

Sign up to request clarification or add additional context in comments.

2 Comments

LukeHennerly: Yay, that worked. You are awesome ! Any() worked. I agree that Any() is more efficient, but I guess Where() queries how I was using them with MongoDb are not supported ? Either way, I'm excited that I can do multiple nested LINQ queries within Mongo now. Thanks again Luke !
@AriesOnTheCusp I think it was more that you were calling Count() on the enumerable which was returning which was somehow not supported. Perhaps try Count as a property?
3

You could write you query more efficiently as

var query =  collection.AsQueryable<Company>()
                 .Where(c => c.dealers.Any(d => d.stores.Count == 1);

If the Mongo querty provider is struggling to support IList, you might find

var query =  collection.AsQueryable<Company>()
                 .Where(c => c.dealers.Any(d => d.stores.Count() == 1);

works better. If so, reports of the maturity of MongoDBs query provider are exaggerated.

1 Comment

Thanks Jodrell, would have marked yours as the answer, but I saw Luke's response first.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.