1

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?

1 Answer 1

1

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");
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks that did it! In my scenario I have to keep the existing API (i.e. I cannot modify the filter object model), so I just create a wrapper for the string values of type List<BsonString>, with filter.ItemIds.Select(s => BsonString.Create(s)).ToList(), and then apply the filter as you suggested.

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.