I need to perform search on the documents with a field in range of specific values.
Having following model:
public class Entity { public BsonDocument Body { get; set; } [BsonIgnore] public JObject BodyJson => JObject.Parse(Body.ToJson()); public string Caption { get; set; } }
With counterpart in DB:
{ "_id": { "$oid": "5c5ad9825404a952105a2c7b" }, "Body": { "name": "Test1" }, "Caption": "Entity created for testing purposes", "id": "5c5ad9825404a952105a2c7b", "_ts": 1566318353 }
This code works just fine:
Expression<Func<TypeDefinition, bool>> predicate = entity => new[] { "Test1", "Test2" }.Contains(entity.Caption); IMongoDatabase.GetCollection<Entity>("entities").Find(predicate).ToListAsync();
But when I try to perform search on Body contained properties (as below) - ArgumentException is being thrown:
Expression<Func<TypeDefinition, bool>> predicate = entity => new[] { "Test1", "Test2" }.Contains((string)entity.Body["name"]);
Exception details:
System.ArgumentException: Unsupported filter: Contains(value(System.String[])). at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate(Expression node) at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate(Expression node, IBsonSerializerRegistry serializerRegistry) at MongoDB.Driver.MongoCollectionImpl`1.CreateFindOperation[TProjection](FilterDefinition`1 filter, FindOptions`2 options) at MongoDB.Driver.MongoCollectionImpl`1.FindAsync[TProjection](IClientSessionHandle session, FilterDefinition`1 filter, FindOptions`2 options, CancellationToken cancellationToken) at MongoDB.Driver.MongoCollectionImpl`1.<>c__DisplayClass43_0`1.<FindAsync>b__0(IClientSessionHandle session) at MongoDB.Driver.MongoCollectionImpl`1.<UsingImplicitSessionAsync>d__101`1.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at MongoDB.Driver.IAsyncCursorSourceExtensions.<ToListAsync>d__16`1.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at MyProj.Repositories.EntitiesRepository.<GetLatestMinorVersionAsync>d__7.MoveNext() in C:\projects\MyProj\Repositories\EntitiesRepository.cs:line 125
Taking a brief glance at PredicateTranslator, discovered that TranslatePipelineContains accepts one side of expression only as IFieldExpression. But since I'm using BsonDocument's accessor to retrieve property - MethodCallExpression is being passed:
(System.String).Call ($entity.Body).get_Item("name")