NEST 5.5 Attribute mapping and custom JsonConverter not working


(Kenneth Truyers) #1

We're using Nest 5.5.0 and attribute mapping to create our indices in Elasticsearch. As part of some of our attributes, we're using custom JsonConverters.

We're migrating from 1.7.3, where this mapping was handled correctly. After upgrading, we can see in the mapping that it has mapped the field without using the converter. When we then index a document, the converter is used and the index operation fails.

Example:

Nest and Elasticsearch 1.7.3

// code
public class MyItem
{
    [JsonProperty("start")]
    [JsonConverter(typeof(LocalTimeConverter))]
    public LocalTime Start { get; set; }
}

// index creation
elasticClient.CreateIndex("indexname", d => d.AddMapping<MyItem>(m => m.MapFromAttributes()))

// generated mapping (mapped as how the JsonConverter would output it)
"myitem": {
    "start": {
        "type": "string"
    }
}

Nest and Elasticsearch 5.5.0

// code
public class MyItem
{
    [JsonProperty("start")]
    [JsonConverter(typeof(LocalTimeConverter))]
    public LocalTime Start { get; set; }
}

// index creation
elasticClient.CreateIndexAsync(IndexName<T>(), d => d.Mappings(m => m.Map<MyItem>(mm => mm.AutoMap())));

// generated mapping (essentially a serialized version of the class)
"myitem": {
    "start": {
         "properties": {
            "clockHourOfHalfDay": { "type": "integer"},
            ...
            ...
            "hour": {"type": "integer" }
    }
}

NOTES:

LocalTime is a class from the NodaTime library
The custom LocalTimeConverter takes the LocalTime and outputs a string

How can I force Nest 5.5.0 to take into account the JsonConverter-attribute when generating my mappings?


(Russ Cam) #2

To map LocalTime as a keyword type (which I think is what you want, which will not be analyzed, but still be indexed and searchable), you can use

public class MyItem
{
    [JsonProperty("start")]
    [JsonConverter(typeof(LocalTimeConverter))]
    [Keyword]
    public LocalTime Start { get; set; }
}

And create the index and mapping as you are currently doing.

You could omit the JsonPropertyAttribute too if you wanted as NEST camel cases property names by default.

This produces the mapping

{
  "mappings": {
    "myitem": {
      "properties": {
        "start": {
          "type": "keyword"
        }
      }
    }
  }
}

(Kenneth Truyers) #3

Thanks, that does the trick. I have another use case though where I need to do something similar:

public class MyItem
{
    [JsonProperty("start")]
    [JsonConverter(typeof(LocalTimeConverter))]
    [???]
    public List<LocalTime> StartTimes { get; set; }
}

Which attribute should I use so that it maps StartTimes as an array of strings, rather than an array of objects?


(Russ Cam) #4

Same attribute, [Keyword]. For the purposes of indexing, there is no distinction between a field containing a single primitive value or multiple primitive values of the same type.

Things get different when the property itself has multiple properties however e.g. the property would serialize to a JSON object. In this scenario, you can map a single object property as [Object], and can map a collection of objects property as [Object] or [Nested]. You would choose [Nested] where you needed to retain the association between properties on a single object in a collection.


(system) #5

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.