How to create MongoDB MultiKey index on attribute of items in an array .NET Driver

Viewed 11262

I have a MongoDB collection "foos" containing items which each have an array of "bars". That is, "foo" has the following schema:

{
    "id": UUID
    "name": string
    ...
    "bars": [
        "id": UUID
        "key": string
        ...
    ]
}

I need to create an index on name and bar.key using the MongoDB C# .NET Mongo driver.

I presumed I could use a Linq Select function to do this as follows:

Indexes.Add(Context.Collection<FooDocument>().Indexes.CreateOne(
    Builders<FooDocument>.IndexKeys
        .Descending(x => x.Bars.Select(y => y.Key))));

However this results in an InvalidOperationException:

System.InvalidOperationException: 'Unable to determine the serialization information for x => x.Bars.Select(y => y.Id).'

The Mongo documentation on MultiKey indexes shows how to create such an index using simple dot notation, i.e.

db.foos.createIndex( { "name": 1, "bars.key": 1 } )

However the MongoDB driver documentation seems to suggest that using a Linq function as I'm doing is correct.

How can I create a multikey index on my collection using the MongoDB .NET Driver, preferably using a Linq function?

5 Answers

This appears to be a requested feature for the C# driver, although it hasn't seen any progress lately. That said, someone did submit a rough-and-ready solution there on the JIRA thread, so perhaps that will do the job for you.

You can create a string index and use nameof() in C# 6:

Indexes.Add(Context.Collection<FooDocument>().Indexes.CreateOne($"{nameof(FooDocument.Bars)}.{nameof(Bars.Key)}"));

As of "MongoDB.Driver" Version="2.8.0" syntax has been changed and some of the methods has been deprecated.Following is the way to achieve the same . Please note the CreateOneAsync(new CreateIndexModel<FooDocument>(indexDefinition)); part

var indexDefinition = Builders<FooDocument>.IndexKeys.Combine(
    Builders<FooDocument>.IndexKeys.Ascending(f => f.Key1),
    Builders<FooDocument>.IndexKeys.Ascending(f => f.Key2[-1].Key));


  await collection.Indexes.CreateOneAsync(new CreateIndexModel<FooDocument>(indexDefinition)); 

As per a previous comment, C# driver still doesn't support a strongly typed way of doing multikey indexes.

Also, using something like [-1] seems bit hacky and not really what you're after as it'll substitute it with $.

As such I suggest doing this (as per MongoDB.Driver 2.8.0 onwards):

var indexDefinition = Builders<FooDocument>.IndexKeys.Combine(
    Builders<FooDocument>.IndexKeys.Ascending(f => f.Key1),
    Builders<FooDocument>.IndexKeys.Ascending($"{nameof(FooDocument.Key2)}.{nameof(BarType.Key)}"));

await collection.Indexes.CreateOneAsync(new CreateIndexModel<FooDocument>(indexDefinition), cancellationToken: token); 
Related