serefbilge
serefbilge

Reputation: 1714

Enumerating dynamic hits result using NEST 6.0 for Elasticsearch

The code below was working before Nest 6.0 for enumerating dynamic hits result. But it throws InvalidCastException anymore.

code:

var response = elasticClient.Search<dynamic>(
                        s => s.Query(q => q.QueryString(m => m.Query(elasticQueryModel.QueryString))
                            ).Source(src => src.Includes(f => f.Fields(fields))).Size(querySize).AllTypes().Index(elasticQueryModel.Index));
var hits = response.Hits;
var rows = new List<Dictionary<string, object>>();
foreach (var hit in hits)
{
     var source = (IDictionary<string, Newtonsoft.Json.Linq.JToken>)hit.Source;
     var row = new Dictionary<string, object>();
     foreach (var keyValuePair in source)
     {
            row[keyValuePair.Key] = keyValuePair.Value;
     }
     rows.Add(row);
 }

What is valid casting for hit.Source, or another solution for this code block?

Upvotes: 3

Views: 2345

Answers (2)

Russ Cam
Russ Cam

Reputation: 125528

With NEST 6.x, the dependency on Json.NET is IL merged and internalized within the client. This has been done for a number of reasons, including:

  • Removing the dependency on Json.NET and thus avoiding conflicts with regards to major versions when incorporating NEST into other projects already using Json.NET.
  • Creating a clear boundary between serialization conventions applied to NEST types and any conventions that you may have for your own types
  • Lays the foundations to look at alternative serialization libraries/techniques in the future e.g. async streams, ArrayPool<T>, Span<T>, etc.

This change means that using dynamic as the generic type on Search<T>() will no longer return source documents as Json.NET's JObject, but will be returned as instances of the internal type Nest.Json.Linq.JObject.

If you'd still like to use Json.NET in conjunction with NEST, then there is also the NEST.JsonNetSerializer nuget package that allows you to plug in your own serialization based on Json.NET. (The documentation is still in progress since NEST 6.x has not GA released quite yet).

The simpler scenario here though I think is to use Dictionary<string, object> as the generic parameter to Search<T>()

var response = client.Search<Dictionary<string, object>>(s => s
    .Query(q => q
        .QueryString(m => m
            .Query("username")
        )
    )
    .AllTypes()
);

foreach (var hit in response.Hits)
{
    foreach (var keyValuePair in hit.Source)
    {
        // do something
    }
}

Upvotes: 5

serefbilge
serefbilge

Reputation: 1714

A working solution without casting could be as below. But, it works only for string key value pair.

var response = elasticClient.Search<dynamic>(
                        s => s.Query(q => q.QueryString(m => m.Query(elasticQueryModel.QueryString))
                            ).Source(src => src.Includes(f => f.Fields(fields))).Size(querySize).AllTypes().Index(elasticQueryModel.Index));
var hits = response.Hits;
var rows = new List<Dictionary<string, object>>();
foreach (var hit in hits)
{
     var row = new Dictionary<string, object>();
     foreach (var keyValuePair in hit.Source)
     {
            var pair = keyValuePair.ToString().Split(':');
            var key = pair[0].Replace("\"", "").Trim();
            var value = pair[1].Replace("\"", "").Trim();

            row[key] = value;
     }
     rows.Add(row);
 }

Upvotes: 1

Related Questions