Search code examples
c#json.netinfluxdb

Parsing InfluxDB result using JSON.net


I'm trying to make a command line utility for initializing a InfluxDB database, but I'm pretty new to influx, and C# in general.

With the following response from the Influx DB Database, I'm trying to pretty print this in the console window.

Ideally I would have errors show up in the standard error buffer, and warnings or info's show up in the standard output.

However, when running the code below in a debug environment, messages appears to be in an incorrect format according to several jsonpath checkers that I have used.

JSON input as result.Body

{
  "results": [
    {
      "statement_id": 0,
      "messages": [
        {
          "level": "warning",
          "text": "deprecated use of 'CREATE RETENTION POLICY Primary ON SensorData DURATION 30d REPLICATION 1' in a read only context, please use a POST request instead"
        }
      ]
    }
  ]
}

JSON output as messages prior to transformation:

messages    {{
  "level": "warning",
  "text": "deprecated use of 'CREATE RETENTION POLICY Primary ON SensorData DURATION 30d REPLICATION 1' in a read only context, please use a POST request instead"
}}  Newtonsoft.Json.Linq.JToken {Newtonsoft.Json.Linq.JObject}

As you can see, the messages output is in a nested object {{}} rather then an array as expected...

According to https://jsonpath.curiousconcept.com/ and several other jsonpath checkers, I was expecting something similar to:

[
   {
      "level":"warning",
      "text":"deprecated use of 'CREATE RETENTION POLICY Primary ON SensorData DURATION 30d REPLICATION 1' in a read only context, please use a POST request instead"
   }
]

C#

    private static void PrintResult(IInfluxDataApiResponse result)
    {
        var output = result.Success ? System.Console.Out : System.Console.Error;
        output.WriteLine("["+result.StatusCode + "] : "+result.Body);
        var json = JObject.Parse(result.Body);
        var messages = json.SelectToken("$.results[*].messages[*]"); //outputs an array of messages if exists. e.g. [{level:warning,text:test}]
        if (messages != null)
        {
            var transformed = messages.Select(m => new { level = (string)m["level"], text = (string)m["text]"] }).ToList();
            foreach (var msg in transformed)
            {
                output.WriteLine($"[{result.StatusCode}] : {msg.level} - {msg.text}");
            }
        }

    }

Solution

  • For my uses at least, using var messages =

    json.SelectTokens("$.results[*].messages[*]"); 
    

    rather then

    json.SelectToken("$.results[*].messages[*]"); 
    

    allowed me to workaround the issue, as I could then treat the result as a C# enumerable, as opposed to special casing 1 result vs many results for SelectToken as it seems to flatten single results into an object, where as other implementations would have it be an array.