Querying JSON with JSON .NET - c#

{
"kind": "folderTree",
"data":
[
{
"id": "IEAAALNZI7777777",
"title": "Root",
"childIds":
[
"IEAAALNZI4ADAKBQ",
"IEAAALNZI4ADAMBQ",
"IEAAALNZI4ADAMBR"
],
"scope": "WsRoot"
},
{
"id": "IEAAANE7I7777777",
"title": "Root",
"childIds":
[
"IEAAANE7I4AC2NTX"
],
"scope": "WsRoot"
},
{
"id": "IEAAALNZI7777776",
"title": "Recycle Bin",
"childIds":
[
"IEAAALNZI4ADALZ2",
"IEAAALNZI4ADAL52",
"IEAAALNZI4ADALR3"
],
"scope": "RbRoot"
}
]
}
Im trying to query the following json structure, searching the child items I want to return the id for a given title.
I am trying something like this:
var folder = json["data"].Children().Where(x => x["Title"] == "Root");
But I'm not sure of the correct syntax

You can use SelectTokens to query LINQ to JSON objects. It supports JSONPath query syntax including wildcards. You can then further narrow down the search with a Where clause:
var folders = json.SelectTokens("data[*]").Where(t => (string)t["title"] == "Root").ToList();
It also supports filtering of array entries based on property values if you don't want the extra Where clause:
var folders = json.SelectTokens("data[?(#.title == 'Root')]").ToList();
Both of the above do the same thing. Incidentally, you've got two folders whose title is "Root" in your JSON, so your query will return multiple results.

Related

How to access inner properties of a Json Object?

I am learning C# and I am trying to parse json/xml responses and check each and every key and value pair. For xml I am converting to json so I have only one function/script to work with both cases. My issue is that I am working with a wide range of json responses which are not similar and there may be arrays in some of the json response. I have tried accessing the "Count" of the json object as a way to check for arrays.
Note: The responses will vary. This example is for Products > Product > name, quantity and category. The next response will change and can be like Country > State > Cities and so on. I cannot rely on creating classes since all responses are going to be different. Plus I am working on automating it so it should be able to handle anything thrown at it.
Sample Json I am working with:
{
"products": {
"product": [
{
"name": "Dom quixote de La Mancha",
"quantity": "12",
"category": "Book"
},
{
"name": "Hamlet",
"quantity": "3",
"category": "Book"
},
{
"name": "War and Peace",
"quantity": "7",
"category": "Book"
},
{
"name": "Moby Dick",
"quantity": "14",
"category": "Book"
},
{
"name": "Forrest Gump",
"quantity": "16",
"category": "DVD"
}
]
}
The way I am accessing the count, name and value is as follows:
dynamic dyn = JsonConvert.DeserializeObject<dynamic>(jsonText);
foreach (JProperty property in dyn.Properties())
{
string propname = property.Name;
var propvalue = property.Value;
int count = property.Count;
}
Is there a way to access these without going through the foreach loop like int count = dyn.Count ? All I am getting from this is null instead of actual values.
For the above example my end result will be like:
This responses contains products> product> 5 x (name, quantity, category)
The QuickWatch for the object:
QuickWatch for dyn object
Try to deserialize your JSON into JObject like below:
var jObject = JsonConvert.DeserializeObject<JObject>(jsonText);

C# How to combine multiple JSON arrays that are part of a List?

What has been done so far?
I am working on dividing up the number of records into 3 batches and processing them in parallel to increase the performance. However, after processing the batches in parallel I would also like to save the outcome (JSON string) of the processed records in a variable.
As you can see below, I first initialize the variable as List of string and then run the foreach loop which saves the processed outcome as mentioned below.
List<string> responseOutcome = new List<string>();
Parallel.ForEach(recordBatches, batch => {
responseOutcome.Add(response1.Content);
});
Result in List responseOutcome comes as:
responseOutcome[0]
[
{
"Name": "Sample1",
"ID": "123"
},
{
"Name": "Sample2",
"ID": "394"
}
],
responseOutcome[1]
[
{
"Name": "Sample5",
"ID": "384"
},
{
"Name": "Sample6",
"ID": "495"
}
],
responseOutcome[2]
[
{
"Name": "Sample3",
"ID": "473"
},
{
"Name": "Sample4",
"ID": "264"
}
]
What I would like to achieve?
Now I would like to take the value of responseOutcome which is multiple arrays of JSON string and merge them into one big JSON string.
Final Output
[
{
"Name": "Sample1",
"ID": "123"
},
{
"Name": "Sample2",
"ID": "394"
},
{
"Name": "Sample5",
"ID": "384"
},
{
"Name": "Sample6",
"ID": "495"
},
{
"Name": "Sample3",
"ID": "473"
},
{
"Name": "Sample4",
"ID": "264"
}
]
I looked into several similar cases but they weren't nearly similar. Like:
How do I merge multiple json objects
How do I combine two arrays from two JObjects in Newtonsoft JSON.Net?
Any help/guidance will be great!!
Using Newtonsoft, you can create a JArray from each of your responses. Then you can flatten the hierarchy using linq's SelectMany method and re-serialize the object.
Try this:
var obj = responses.Select(r => JArray.Parse(r.Trim(','))).SelectMany(token => token);
string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
There are probably more efficient ways to do this if you want to do pure string manipulation, but using Newtonsoft, I would deserialize, merge and then re-serialize.
Create a small POCO model:
public class ResponseOutcomeModel
{
public string ID { get; set; }
public string Name { get; set; }
}
Then deserialize to this model, merge and reserialize to JSON as a single list.
var outcomeList = new List<ResponseOutcomeModel>();
foreach (var i in responseOutcome)
{
outcomeList.AddRange(JsonConvert.DeserializeObject<List<ResponseOutcomeModel>>(i.Trim().TrimEnd(',')));
}
var finalJson = JsonConvert.SerializeObject(outcomeList);
Note, the Time/TrimEnd is used if the trailing commas in your example are really there in your responseOutcome array (at the end of each element in the array). The call to DeserializeObject will complain if you leave the commas in there.

Linq query to Json string

starting from a JObject I can get the array that interests me:
JArray partial = (JArray)rssAlbumMetadata["tracks"]["items"];
First question: "partial" contains a lot of attributes I'm not interested on.
How can I get only what I need?
Second question: once succeeded in the first task I'll get a JArray of duplicated items. How can I get only the unique ones ?
The result should be something like
{
'composer': [
{
'id': '51523',
'name': 'Modest Mussorgsky'
},
{
'id': '228918',
'name': 'Sergey Prokofiev'
},
]
}
Let me start from something like:
[
{
"id": 32837732,
"composer": {
"id": 245,
"name": "George Gershwin"
},
"title": "Of Thee I Sing: Overture (radio version)"
},
{
"id": 32837735,
"composer": {
"id": 245,
"name": "George Gershwin"
},
"title": "Concerto in F : I. Allegro"
},
{
"id": 32837739,
"composer": {
"id": 245,
"name": "George Gershwin"
},
"title": "Concerto in F : II. Adagio"
}
]
First question:
How can I get only what I need?
There is no magic, you need to read the whole JSON string and then query the object to find what you are looking for. It is not possible to read part of the JSON if that is what you need. You have not provided an example of what the data looks like so not possible to specify how to query.
Second question which I guess is: How to de-duplicate contents of an array of object?
Again, I do not have full view of your objects but this example should be able to show you - using Linq as you requested:
var items = new []{new {id=1, name="ali"}, new {id=2, name="ostad"}, new {id=1, name="ali"}};
var dedup = items.GroupBy(x=> x.id).Select(y => y.First()).ToList();
Console.WriteLine(dedup);

How can I use a JSONPath expression as a filter inside another JSONPath expression?

I want to select objects from a JSON string by filtering using a JSONPath expression with another expression embedded in the filter. In other words, I want to filter for a value that is present elsewhere in the JSON data.
For example:
In the following JSON data there is a value in $.Item.State.stepId (currently "QG2.0"). I need to have a JSONPath expression that selects values based on this value, like this:
$..Step[?(#.stepId==$Item.State.stepId)].actionDate
But this will not return any results. If I use the string ("QG2.0") directly like this:
$..Step[?(#.stepId=='QG2.0')].actionDate
it will return the required data.
What's wrong, or is it not even possible? My JSON is below:
{
"Item": {
"Common": {
"folio": "PSH-000016020",
"setName": "123-XZ200-1",
"wfId": "Kat1_002",
"wfIssue": "002",
"wfIdIssue": "Kat1_002.002"
},
"State": {
"status": "IN WORK",
"stepId": "QG2.0",
"stepDescription": "Validation"
},
"Participants": {
"Participant": [
{
"role": "PR",
"roleDescription": "Product Responsible",
"loginName": "marc102",
"email": "mark#abc.de"
}, {
"role": "CR",
"roleDescription": "Chapter Responsible",
"loginName": "uli26819",
"email": "uli#abc.de"
}
]
},
"Steps": {
"Step": [
{
"stepId": "QG1.0",
"stepTitle": "Preparation",
"actionDate": "2016-06-28T10:28:09",
"actionDueDate": "",
"actionBy_Name": "Marc",
"actionBy_Account": "marc102",
"action": "complete",
"Comment": ""
}, {
"stepId": "QG2.0",
"stepTitle": "Check Requirements",
"actionDate": "2016-08-08T14:17:04",
"actionDueDate": "",
"actionBy_Name": "Uli",
"actionBy_Account": "uli26819",
"action": "complete",
"Comment": ""
}
]
}
}
}
I don't think Json.Net's implementation of JSONPath supports this concept.
However, you can still get the information you want if you break the query into two steps:
JObject obj = JObject.Parse(json);
JToken stepId = obj.SelectToken("Item.State.stepId");
JToken actionDate = obj.SelectToken(string.Format("$..Step[?(#.stepId=='{0}')].actionDate", stepId));
Console.WriteLine(actionDate.ToString());
Fiddle: https://dotnetfiddle.net/KunYTf

MongoDB remove a subdocument document from a subdocument

I use 10gen C# driver for MongoDB and I would like to remove a subdocument from a subdocument. I don't know how to do it.
Here's an example of what looks like my document
{
"_id": "binary_stuff",
"Name": "MyApplication",
"Settings": [
{
"_id": "binary_stuff",
"Key": "ImportDirectory",
"Value": "C:\data",
"Overrides": [{
"_id": "binary_stuff",
"Name": "PathDirectory",
"Value": "C:\anotherData"
}]
},
}
And I want to delete the Override which Name is PathDirectory. Here's the query I wrote but it doesn't work. I have no error.
var query = Query.And(Query.EQ("_id", applicationId), Query.EQ("Settings.Key", "ImportDirectory"), Query.EQ("Settings.$.Overrides.Name", "PathDirectory"));
Run(database => database.Applications().Remove(query));
Thanks for any help.
John
you should to use $pull operation for delete item from array.
var query = Query.And(Query.EQ("_id", applicationId),
Query.EQ("Settings.Key", "ImportDirectory"));
var update = Update.Pull("Settings.$.Overrides", new BsonDocument(){
{ "Name", "PathDirectory" }
});
database.Applications().Update(query, update);

Categories