Search code examples
c#mongodbmongodb-querymongodb-.net-driver

Mongodb C# driver Perform string contains query on a property in an embedded document


I have the below simplified model:

public class Entity
{
    public Guid Id { get; set; }

    public IList<ComponentProperty> Components { get; private set; }

}

public class ComponentProperty
{
    public string PropertyName { get; set; }

    public string Value { get; set; }

}

I want to be able to find any entity whose property value string contains the search string, and to that end I wrote the following query, based on recommendation here, which implicitly uses Regex:

var query = _context.GetCollection<Entity>()
                        .AsQueryable()
                        .Where(t => t.Components.Any(c => c.Value.ToLower() == queryOptions.Filter));

This query produces the following json, and (incorrectly) returns 0 rows:

aggregate([{ "$match" : { "Components" : { "$elemMatch" : { "Value" : /^'green'$/i} } } }])

However, the hand-crafted query that produces the correct results is the below:

aggregate([{ "$match" : { "Components" : { "$elemMatch" : { "Value" :  {$regex: '.*green.*' } } } } }])

Perhaps, there is something I have overlooked in my approach using the c# driver, and any pointers will be much appreciated.


Solution

  • change your where clause to this:

    .Where(e => e.Components.Any(c => c.Value.ToLower().Contains(queryOptions.Filter)))
    

    which produces this aggregation:

    db.Entity.aggregate([
        {
            "$match": {
                "Components.Value": /green/is
            }
        }
    ])
    

    here's a test program:

    using MongoDB.Entities;
    using MongoDB.Entities.Core;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace StackOverFlow
    {
        public class Ntity : Entity
        {
            public IList<ComponentProperty> Components { get; set; }
        }
    
        public class ComponentProperty
        {
            public string PropertyName { get; set; }
    
            public string Value { get; set; }
    
        }
    
        public static class Program
        {
            private static void Main()
            {
                new DB("test");
    
                new Ntity
                {
                    Components = new List<ComponentProperty> {
                        new ComponentProperty {
                            PropertyName = "test",
                            Value = "the RED color" }
                    }
                }.Save();
    
                new Ntity
                {
                    Components = new List<ComponentProperty> {
                        new ComponentProperty {
                            PropertyName = "test",
                            Value = "the Green color" }
                    }
                }.Save();
    
                var result = DB.Queryable<Ntity>()
                               .Where(e => e.Components.Any(c => c.Value.ToLower().Contains("green")))
                               .ToList();
            }
        }
    }