4

My documents have an array property in them. Lets call it arrayProperty something like this:

 {
  _id: mongoObjectIdThingy,
  arrayProperty: [
    {string1: "aString",otherProperty:"somethingelse"},
    {string1: "aString2",otherProperty:"somethingelse"}
  ]
}

I'm using the mongodb c# driver. I want to find all documents that contain any of a list of string1 values. For example say I have a list of strings:

["a","b","aString"]

I want the query to return the above document. I've tried this:

    var builder = Builders<MyObject>.Filter;

    var listToFind = new List<string>{"a","b","aString"};


    return builder.ElemMatch(o => o.arrayProperty,
        d => listToFind.Contains(d.string1));

But got this exception:

Unsupported filter: Contains(value(System.Collections.Generic.List`1[System.String]))

It seems like I can't do a contains linq expression in the driver's filter expression. How does one write this type of query in mongoDB with C#?

1
  • 1
    it works to me, which version are you using? Commented Feb 17, 2020 at 21:26

2 Answers 2

5

I believe you are looking for the In FilterDefinition, which would make your Builder look like this;

return Builders<MyObject>.Filter.ElemMatch(
            o => o.arrayProperty,
            Builders<ArrayProperty>.Filter.In(y => y.string1, listToFind));

This builds this query

db.MyObject.find({ "arrayProperty" : { "$elemMatch" : { "string1" : { "$in" : ["a", "b", "aString"] } } } })

To be able to use the Regex you would have to build a different query (I'm not on coffee so this is without any warranty)

        var listToFind = new List<string> { "a", "b", "astring" };

        var regexList = listToFind.Select(x => new BsonRegularExpression(x, "i"));

        var filterList = new List<FilterDefinition<MyObject>>();
        foreach (var bsonRegularExpression in regexList)
        {
            FilterDefinition<MyObject> fil = Builders<MyObject>.Filter.ElemMatch(o => o.arrayProperty, Builders<ArrayProperty>.Filter.Regex(
                 x => x.string1,
                 bsonRegularExpression));

            filterList.Add(fil);
        }


        var orFilter = Builders<MyObject>.Filter.Or(filterList);

        var result = collection.Find(orFilter).ToList();

Which builds the follow query

db.MyObject.find({ "$or" : [{ "arrayProperty" : { "$elemMatch" : { "string1" : /a/i } } }, { "arrayProperty" : { "$elemMatch" : { "string1" : /b/i } } }, { "arrayProperty" : { "$elemMatch" : { "string1" : /astring/i } } }] })
Sign up to request clarification or add additional context in comments.

7 Comments

Where is the In Filter definition used in your answer?
Good point, I wrote the wrong part here. Updated now. @cobolstinks
hmm having difficulty implementing this. Is Builders<ArrayProperty> the type of my object array? or is that some MongoDB driver built in class?
It's the class I assumed your model had for the arrayProperty array. Could your post your models? To answer your question, yes it's the type of your object array.
ok cool that worked thanks! However one last wrinkle is i want the search to be case insensitive. Is there a flag to pass in the In clause for this?
|
1

Another workaround is using "Any" instead of "Contain".

return builder.ElemMatch(o => o.arrayProperty,
        d => listToFind.Any(y => y == d.string1));

Comments

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.