Iterating through a nested JSON Array in C# with Newtonsoft - c#

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);
}
}

Related

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";
}

Trouble obtaining object values within an array using 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"]);
}

How to compare single property from 2 array using c# execution time should be minimum

I have two arrays variables and values like below
arraydata1 =
[
{
"id": "1",
"name": "aaa"
},
{
"id": "2",
"name": "bbb"
},
{
"id": "3",
"name": "ccc"
},
{
"id": "4",
"name": "ddd"
},
{
"id": "12",
"name": "aaa"
}
]
and
arraydata2 =
[
{
"id": "111",
"tablename": "aaa"
},
{
"id": "222",
"tablename": "bbb"
}
]
I want to compare arraydata1.name == arraydata2.tablename and if matching then form new array from arraydata1 .
output is -
[
{
"id": "1",
"name": "aaa"
},
{
"id": "2",
"name": "bbb"
},
{
"id": "12",
"name": "aaa"
}
]
I have more than 2000+ records to compare in arraydata1 how to reduce time as well. I can use normal foreach but it will take too much time to compare.
I was doing inside logic app using 2 foreach so it is taking time. so i thought better to use c# code.
One Linq solution could look like this:
var tableNameKeys = arraydata2.Select(t => t.tablename).ToHashSet();
var resultArray = arraydata1.Where(x => tableNameKeys.Contains(x.name)).ToArray();
The advantage of this approach is that HashSet.Contains
... is an O(1) operation.
Result:

Zip collections matching by ID

This is a repost of a previous question that was wrongly closed as a duplicate:
Say I have two collections of the same type similar to the following:
OldCollection: [{ID: 1, other props}, {ID: 2, other props}, {ID: 3, other props}]
NewCollection: [{ID: 1, other props}, {ID: 3, other props}, {ID: 4, other props}]
Is there a way to zip the collections matching ID's to get a Tuple result like the following:
[{OLD-ID1, NEW-ID1},
{OLD-ID2, null},
{OLD-ID3, NEW-ID3},
{null, NEW-ID4}]
So basically I want to zip the collections together matching on ID and if only one collection has an entry with a particular ID the Tuple should fill in null for that spot.
IMPORTANT: This is not a duplicate of the full outer join solution. I do not want to combine my results so that Col1-ID1 gets merged with Col2-ID1. I Just want to Tuple them so I can see them side by side. Think of it as Collection 1 is the old values and Collection 2 is the new values. I want them to be paired up into Tuples so I can see ID1 and ID3 were updated, ID2 was removed, and ID4 was added.
Here is a DotNetFiddle example that almost does what I want.
The results of that fiddle is:
[
{
"Item1": {
"id": 1,
"name": "firstOld"
},
"Item2": {
"id": 1,
"name": "firstNew"
}
},
{
"Item1": {
"id": 2,
"name": "secondOld"
},
"Item2": {
"id": 3,
"name": "thirdNew"
}
},
{
"Item1": {
"id": 3,
"name": "thirdOld"
},
"Item2": {
"id": 4,
"name": "fourthNew"
}
},
{
"Item1": null,
"Item2": {
"id": 5,
"name": "fifthNew"
}
}
]
What I want is this:
[
{
"Item1": {
"id": 1,
"name": "firstOld"
},
"Item2": {
"id": 1,
"name": "firstNew"
}
},
{
"Item1": {
"id": 2,
"name": "secondOld"
},
"Item2": null
},
{
"Item1": {
"id": 3,
"name": "thirdOld"
},
"Item2": {
"id": 3,
"name": "thirdNew"
}
},
{
"Item1": null,
"Item2": {
"id": 4,
"name": "fourthNew"
}
},
{
"Item1": null,
"Item2": {
"id": 5,
"name": "fifthNew"
}
}
]
You want a full-outer-join anyway, but you could use this easy approach:
var oldByID = oldCollection.ToDictionary(x => x.Id);
var newByID = newCollection.ToDictionary(x => x.Id);
IEnumerable<int> allIds = oldByID.Keys.Union(newByID.Keys);
var oldAndNew = allIds.Select(id =>
(Old: oldByID.TryGetValue(id, out var oldObj) ? oldObj : null,
New: newByID.TryGetValue(id, out var newObj) ? newObj : null));
So first create two dictionaries to lookup the old and new objects via Id efficiently. Then collect all Id's and use Select to get the old/new object with each Id. If it's not available in the dictionary it will assign null to the tuple item.

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