Trouble obtaining object values within an array using C# - c#

I am using C# and unable to obtain JSON data values for the JSON below:
I am trying to obtain all name value pairs for:
body.quotes.vehicle.key
and
body.quotes.prices.pricing-fixed.price
The JSON contains several of these 'vehicle' and 'prices' objects (repeated for different vehicle types) although I've only included one below to keep the code succinct.
I can see that "quotes" is an array containing multiple vehicle and pricing objects but I'm stuck on the fact that each of the containing objects doesn't seem to have a direct name value pair so I can't work out how to obtain the values I need.
{
"version": 243,
"code": "0",
"body": {
"quotes": [
{
"vehicle": {
"id": null,
"title": "Any Vehicle",
"key": "R4",
"description": "4 Seater",
"group": "NOMAP"
},
"prices": {
"pricing-fixed": {
"id": "18277",
"title": "FIXED",
"type": "fixedfare",
"alt": false,
"cost": 25,
"price": 25,
"tip": 0,
"commission": 0.5,
"auto": "1",
"priority": 1,
"schedulable": "1",
"for_account": false,
"audit": {
"zonecharges": []
},
"attributeextras_cost": 0,
"attributeextras_price": 0,
"round_robin": 0,
"waitAndReturn": false,
"prebooking_extra_price": "0.00",
"waitAndReturnCostDiscount": 0,
"waitAndReturnPriceDiscount": 0
}
}
},
{
"vehicle": { ...//etc.
I have tried the following C# code but (string)iCabbiVehicleJson["vehicle.key"] is null. (I believe this line is the problem?)
Code snippet:
string jsonResponseAsString = returnJson.ToString();
JObject iCabbiResponseJson = JObject.Parse(jsonResponseAsString);
List<iCabbiQuoteVehicleFare> vehicleFares = new List<iCabbiQuoteVehicleFare>();
foreach (JToken vehicleFare in iCabbiResponseJson.SelectToken("body.quotes"))
{
try
{
JObject iCabbiVehicleJson = JObject.Parse(vehicleFare.ToString());
string vehicleKey = (string)iCabbiVehicleJson["vehicle.key"];
decimal fare = (decimal)iCabbiVehicleJson["prices.pricing-fixed.price"];
vehicleFares.Add(new iCabbiQuoteVehicleFare
{
VehicleKey = vehicleKey,
Fare = fare
});
}
catch (Exception ex)
{
string errorMessage = ex.Message;
}
}
the variable vehicleFares actually returns the below. That double curly braces is most likely the issue...
{{
"vehicle": {
"id": null,
"title": "Any Vehicle",
"key": "R4",
"description": "4 Seater",
"group": "NOMAP"
},
"prices": {
"pricing-fixed": {
"id": "18277",
"title": "FIXED",
"type": "fixedfare",
"alt": false,
"cost": 25,
"price": 25,
Thanks.

The problem is the square bracket indexer syntax of JToken does not support dotted property paths. You need to use the SelectToken() method for that.
Change these lines:
string vehicleKey = (string)iCabbiVehicleJson["vehicle.key"];
decimal fare = (decimal)iCabbiVehicleJson["prices.pricing-fixed.price"];
to this:
string vehicleKey = (string)iCabbiVehicleJson.SelectToken("vehicle.key");
decimal fare = (decimal)iCabbiVehicleJson.SelectToken("prices.pricing-fixed.price");
Fiddle: https://dotnetfiddle.net/nkSu5y

I think you can just treat them as dynamic and iterate over them using a for loop. I just did something like this using your example data, and it seemed to work.
Fiddle
// Where the data variable holds your json string
var json = JsonConvert.DeserializeObject<dynamic>(data);
var count = json.body.quotes.Count;
for(var i = 0; i < count; i++) {
Console.WriteLine(json.body.quotes[i].vehicle.key);
Console.WriteLine(json.body.quotes[i].prices["pricing-fixed"]);
}

Related

NEST Elastic search empty values in Documents result

Elastic search noob question.
After reading some questions on SO I figured out to POST some data to my Index but I'm having some trouble getting back results.
I'm getting one document (as expected) but all properties are empty. The number of bytes 740 match the number of bytes received in Postman. I suspect the data isn't mapped right somehow..
Code:
var client = CreateCloudClient();
var indexName = "index-b";
var mustClauses = new List<QueryContainer>();
mustClauses.Add(new WildcardQuery
{
Field = new Field("FirstName"),
Value = "*ralf*"
});
var searchRequest = new SearchRequest<ProfileEntity>(indexName)
{
Query = new BoolQuery { Must = mustClauses }
};
var searchResponse = await client.SearchAsync<ProfileEntity>(searchRequest);
if (searchResponse.Hits.Any())
{
var person = searchResponse.Hits.First();
}
Debugger result
When using Postman:
GET ../westeurope.azure.elastic-cloud.com:9243/index-b/_search
{
"query": {
"bool": {
"must": [
{
"wildcard": {
"FirstName": "*ralf*"
}
}
]
}
}
}
I'm getting:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "index-b",
"_type": "_doc",
"_id": "0ec623e7-3837-4e83-808d-fed01398d1ab",
"_score": 1.0,
"_source": {
"Id": 0,
"ProfileId": "0ec623e7-3837-4e83-808d-fed01398d1ab",
"FirstName": "Ralf",
"LastName": "de K",
"BirthDate": "1999-09-19T00:00:00Z",
"BirthPlace": "Zwolle",
"BirthPlaceLocation": {
"Longitude": 41.9074,
"Latitude": -78.7911
},
"City": "Zwolle",
"Email": "email#example.org",
"ObjectIdentifier": "0ec623e7-3837-4e83-808d-fed01398d1ab",
"MobileNumber": "06123123123",
"Height": 2,
"BodyBuild": 0,
"Ethnicity": 8,
"Education": 3,
"Gender": 2,
"Created": "0001-01-01T00:00:00",
"Updated": "0001-01-01T00:00:00"
}
}
]
}
}
It was my own mistake. I used ElasticLowLevelClient to add a new index and I (probably) should have used ElasticClient because the first adds the index with pascal casing and the latter camel casing. Could be a config/setting but usinf ElasticClient fixes my problem.

Add a field into JSON array C#

Here is my json Array, i want to add a new field in array but i dont know how to loop it
{
"data": {
"pasca": [
{
"code": "PDI1231",
"name": "Water Bottle",
"status": 1,
"price": 2500,
"type": "plastic"
},
{
"code": "PDI9999",
"name": "Soccel Ball",
"status": 1,
"price": 99123,
"type": "plastic"
}
]
}
}
i want to add a new field in pasca array like this
"pasca": [
{
"code": "PDI1231",
"name": "Water Bottle",
"status": 1,
"price": 2500,
"type": "plastic",
"new_field_1": "new value_1",
"new_field_2": "new value_2"
}
]
If you are using Newtosoft's Json.NET it can be done as simple as that:
var jObj = JsonConvert.DeserializeObject<JObject>(json);
foreach(var el in jObj["data"]["pasca"])
{
el["new_field_1"] = "new value_1";
}

Iterating through a nested JSON Array in C# with Newtonsoft

I have a block of JSON as follows:
[
{
"id": 1,
"name": "Section1",
"project_id": 100,
"configs": [
{
"id": 1000,
"name": "myItem1",
"group_id": 1
}
]
},
{
"id": 2,
"name": "Section2",
"project_id": 100,
"configs": [
{
"id": 1001,
"name": "myItem2",
"group_id": 2
},
{
"id": 1002,
"name": "myItem3",
"group_id": 2
},
{
"id": 1003,
"name": "myItem4",
"group_id": 2
}
]
},
{
"id": 3,
"name": "Section3",
"project_id": 100,
"configs": [
{
"id": 1004,
"name": "myItem5",
"group_id": 5
},
]
}
]
I have pulled it into Memory as a JArray.
I need to iterate through this such that I'm grabbing a list of ids and name from only the config sub-arrays. Ideally, I'll end up with something like this:
1000, myItem1
1001, myItem2
1002, myItem3
1003, myItem4
1004, myItem5
I'm having a hard time understanding what Newstonsoft calls a JObject vs a JArray, or how to access the various parts of each of those data structures. What I have right now is as follows:
foreach (JObject config in result["configs"])
{
string id = (string)config["id"];
string name = (string)config["name"];
string gid = (string)config["group_id"];
Console.WriteLine(name + " - " + id + " - " + gid);
}
This does not work, but I hope it illustrates what my end goal is. I've been unable to piece together how to accomplish this goal.
A JObject is an object (analogous to a class):
{
"a": 1,
"b": true
}
A JArray is a JSON array, and contains multiple JObject entities:
[
{
"a": 1,
"b": true
},
{
"a": 2,
"b": true
}
]
The root of a JSON document can be an object, or an array. In your case, it's an array.
The following code and fiddle reveals that your code is fine, provided that you deserialize the document as what it is - an array.
string json = "[{\"id\":1,\"name\":\"Section1\",\"project_id\":100,\"configs\":[{\"id\":1000,\"name\":\"myItem1\",\"group_id\":1}]},{\"id\":2,\"name\":\"Section2\",\"project_id\":100,\"configs\":[{\"id\":1001,\"name\":\"myItem2\",\"group_id\":2},{\"id\":1002,\"name\":\"myItem3\",\"group_id\":2},{\"id\":1003,\"name\":\"myItem4\",\"group_id\":2}]},{\"id\":3,\"name\":\"Section3\",\"project_id\":100,\"configs\":[{\"id\":1004,\"name\":\"myItem5\",\"group_id\":5},]}]";
JArray obj = Newtonsoft.Json.JsonConvert.DeserializeObject<JArray>(json);
foreach (var result in obj)
{
foreach (JObject config in result["configs"])
{
string id = (string)config["id"];
string name = (string)config["name"];
string gid = (string)config["group_id"];
Console.WriteLine(name + " - " + id + " - " + gid);
}
}

Parsing LuisResult to get values field

I have a LuisResult variable called result that has JSON info like
{
"query": "what is twenty * three",
"topScoringIntent": {
"intent": "Multiplication",
"score": 0.740870655
},
"intents": [
{
"intent": "Multiplication",
"score": 0.740870655
},
{
"intent": "Subtraction",
"score": 0.04339512
},
{
"intent": "None",
"score": 0.0164503977
},
{
"intent": "addition",
"score": 0.0126439808
},
{
"intent": "Division",
"score": 0.0108866822
}
],
"entities": [
{
"entity": "twenty",
"type": "builtin.number",
"startIndex": 8,
"endIndex": 13,
"resolution": {
"value": "20"
}
},
{
"entity": "three",
"type": "builtin.number",
"startIndex": 17,
"endIndex": 21,
"resolution": {
"value": "3"
}
}
]
}
I'm trying to access the "value" field under "resolution" since it converts string representations of numbers to digit representation. At the moment I'm just trying to get the first value. I've tried to extract the value this way
var valuesEntity = result.Entities; //IList of all entities
string s = "";
s = valuesEntity[i].Resolution.Values.ToString(); //extract value field??
await context.PostAsync($"{s}"); //post to emulator
This prints out System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.String]
to me. What am I missing to be able to get the "values" field?
Try
valuesEntity[i].Resolution.Values[0].ToString();
Values is a collection of strings.
You can also use linq and do:
valuesEntity[i].Resolution.Values.FirstOrDefault();

Find field with specific key in Json

In my c# project I use Json.net Library.
I have long Json with many subfields, for ex:
{
"count": 10,
"Foo1": [
{
"id": "1",
"name": "Name1"
},
{
"id": "2",
"name": "Name3"
},
{
"id": "3",
"name": "Name4"
}
],
"Foo2": [
{
"id": "4",
"name": "Name3",
"specific_field": "specific_values1"
},
{
"id": "5",
"name": "Name3",
"specific_field": "specific_values2"
},
{
"id": "6",
"name": "Name3",
"specific_field": "specific_values3"
}
],
"Foo3": [
{
"id": "7"
},
{
"id": "8"
},
{
"id": "9"
}
]
}
And I need to get List of all specific_field (id 4-6), but cant deserialized json to object, because Foo1, Foo2 ... changed dynamically.
I want to know, is this possible to get values of specific_field when i have only json?
I think, I found solution:
var list = new List<string>();
var result = ((JToken)json);
foreach (var res in result)
{
list.AddRange(from foo in res.First let ret = foo["specific_field"] where (dynamic) ret != null select foo["specific_field"].ToString());
}
In comment, provide, what do you think about it?
You could use dynamics:
string json = "your JSON string comes here";
dynamic deserializedValue = JsonConvert.DeserializeObject(json);
var values = deserializedValue["Foo2"];
for (int i = 0; i < values.Count; i++)
{
Console.WriteLine(values[i]["specific_field"]);
}

Categories