Naftis Naftis - 3 months ago 82
C# Question

MongoDB C# - LINQ Contains against a string array throws ArgumentException

I'm new to MongoDB so this might be a naive question, yet I have not found any relevant/up to date information by googling around: I am trying to use the MongoDB C# driver (version 2.2.4) to compose a LINQ-based query, one piece at a time, from a received

filter
POCO object, like this:

IQueryable<BsonDocument> parts = collection.AsQueryable();
if (filter.Name != null)
parts = parts.Where(d => d["Name"].Equals(filter.Name));
// ... etc; I'll then call ToList() to get results ...


Now, one of my
filter
properties is a string array, meaning that I should match any document whose field
Vendor
(a string property in the MongoDB document) is equal to any of the strings in the array (like MongoDB native
$in
: https://docs.mongodb.com/manual/reference/operator/query/in/).

To this end, I tried with
Contains
(the special case for a 1-sized array is just an optimization):

if (filter.Vendors != null && filter.Vendors.Length > 0)
{
parts = filter.Vendors.Length == 1
? parts.Where(d => d["Vendor"].Equals(filter.Vendors[0]))
: parts.Where(d => filter.Vendors.Contains(d["Vendor"].AsString));
}


This compiles, but throws an
ArgumentException
: "Expression of type 'MongoDB.Bson.BsonValue' cannot be used for parameter of type 'System.String' of method 'Boolean Contains[String](System.Collections.Generic.IEnumerable`1[System.String], System.String)'".

Looking at http://mongodb.github.io/mongo-csharp-driver/2.2/reference/driver/crud/linq/, there is nothing about
Contains
or
$in
; yet, from
https://jira.mongodb.org/browse/CSHARP-462
it seems that the driver should now be capable of handling that method.

BTW, the same happens if I slightly change the code to:

parts.Where(d => filter.Vendors.Any(s=> d["Vendor"].Equals(s)));


which does not involve
Contains
at all. The exception message complains about not being able to use
BsonValue
for
string
, yet that
BsonValue
is right a
string
. Could anyone suggest a solution?

Answer

The exception messages dance around the idea of fully embracing BsonValue to let mongo handle the types instead of trying to cast to string. I got it to work having Vendors as type List<BsonValue>.

class Filter
{ 
        public List<BsonValue> Vendors { get; set; }
}

...

var list = parts.Where(d => filter.Vendors.Contains(d["Vendor"]));
foreach (var document in list)
{
    Console.WriteLine(document["Name"]);
}

Another alternative is to map your documents to a C# class instead of using BsonDocument as the collection type.

class MyDocument
{
    public ObjectId Id { get; set; }
    public string Name { get; set; }
    public string Vendor { get; set; }
}
...
var collection = db.GetCollection <MyDocument> ("parts");
Comments