Search code examples
c#.netelasticsearchnest

Elasticsearch mapping DTO after source filtering in .NET


I have a POCO FooIndex that is mapped to an index in elasticsearch and I want to perform a query on this index and return only specific fields. I created a DTO FooStatus that only contains properties with the fields I am returning.

This works fine if the property names in the DTO match the names in the index mapping, as expected, but I would like to have different names for some properties and map them to the index fields. How can I do this?

var searchDescriptor = new SearchDescriptor<FooIndex>()
                       .Index(index)
                       .Source(sf => sf
                                   .Includes(i => i
                                                 .Fields(
                                                     f => f.FooId,
                                                     f => f.FirstName,
                                                     f => f.LastName,
                                                     f => f.PrimaryEmail,
                                                     f => f.UpdatedDate,
                                                     f => f.Statuses)))
                       .Query(q => q
                                  .Bool(b => b
                                            .Filter(f => f
                                                        .Terms(t => t
                                                                    .Field(p => p.Statuses.Select(
                                                                               x => x.blahId))
                                                                    .Terms(reqIds)))));
var results = await _elasticClient.SearchAsync<FooStatus>(searchDescriptor);
return results.Documents;


public class FooStatus
{
    public string FooId { get; set; }
    public string FirstName {get; set;}
    public string LastName {get; set; }
    public string Email {get; set;}              // Map this from FooIndex.PrimaryEmail
    public DateTime? DateModified {get; set; }  // Map this from FooIndex.UpdatedDate
    public List<FooStatus> Statuses { get; set; }
}

Solution

  • I would like to have different names for some properties and map them to the index fields. How can I do this?

    If the properties that you want to map are at the same depth in the object graph, then you can use DataMemberAttribute or PropertyNameAttribute to map fields to differently named properties on the POCO.

    If the properties are at different depths, this isn't something that can be easily done with the built-in serializer. You could have private members with attributes applied that the serializer will deserialize JSON fields to, and public properties with the desired names. The overall shape of the object graph to deserialize would need to be same as FooIndex however e.g. to map FooIndex.Bar.Baz would require the object graph of FooStatus to be three levels deep in order to map Baz.

    To do it with other serializers like JSON.NET and System.Text.Json would require writing a custom JsonConverter, reading each property in turn, and assigning values. It's a fair bit of effort to do, and would require revisiting any time FooStatus' properties need to change.