As of v2.23.0, Expressions accessing Dictionary.Keys are no longer supported via IndexKeysDefinitionBuilder

We are trying to update to the latest Mongo C# Driver to use the new EntityFramework lib, but haven’t been able to get past a breaking change that was bug (or perhaps a bug that was introduce) in v2.23.0. In v2.22.0 and prior, we have been able to pass Dictionary.Keys in an Expression via IndexKeysDefinitionBuilder. For example:

public class Thing
{
  [BsonRepresentation(BsonType.ObjectId)]
  [BsonIgnoreIfDefault]
  public string Id { get; set; }
  public string Name { get; set; }
  public Dictionary<string,string> Attributes { get; set; }
}

// Given the following

protected static IndexKeysDefinitionBuilder<TEntity> Index => Builders<TEntity>.IndexKeys;

// Some data layer code that builds indexes

var collection = database.GetCollection<Thing>("things");

await collection.Indexes.CreateOneAsync(
  new CreateIndexModel<Thing>(
    Index.Combine(
      Index.Ascending(o => o.Name),
      Index.Ascending(o => o.Attributes.Keys))));

Is there a different way to build this Expression now or was this a bug that got introduced? Any guidance is appreciated.

Hi @Clayton_Taylor ,

Welcome to the MongoDB Community forums! Are you trying to index all the attributes with Attributes.Keys or is there an element named Keys? Are you seeing an exception now when you do that? If so then the suspicion is that the LINQ2 provider was translating that to an index field of { "Attributes.Keys" : 1 } which is legal but it wouldn’t do what you expected and index only the 1st field. The LINQ3 provider catches this and throws an exception.

One alternative you can try is to use wildcard indexes. This can be done in the C# Driver as builder.Wildcard(x => x.Attributes). Hope that helps.

Thanks,

Rishit.

Hey @Rishit_Bhatia,

Our code expects to index all of the keys in the target Dictionary; it sounds like maybe it isn’t doing what we expect today. Also, in v2.23.0, we do see an invalid expression exception that gets thrown.

From what I understand about wildcard indexes, they cannot be combined with other fields without the wildcardProjection. Is that true? In other words, how would I achieve my example above with Name added ascending and Attributes added as wildcard?

Thanks in advance for your help

Perhaps something like:

// Given the following
protected static ProjectionDefinitionBuilder<TEntity> Projection => Builders<TEntity>.Projection;

var collection = database.GetCollection<Thing>("things");

await collection.Indexes.CreateOneAsync(
  new CreateIndexModel<Thing>(
    Index.Wildcard(), new CreateIndexOptions<Thing> {
      WildcardProjection = Projection.Combine(
        Projection.Include(o => o.Id),
        Projection.Include(o => o.Name),
        Projection.Include(o => o.Attributes))
    }));

Hi Clayton,

Thanks for raising the ticket. We’ll be investigating this, keep an eye on the ticket for updates.

Thanks,

Rishit.