How to use SelectToken to find value in nested dynamic JSON - c#

I can't figure out how to use JToken to get the "Total Income" amount of "325.00".
I have tried quite a few different lines of code but seem to be missing something obvious.
{
"Rows": {
"Row": [
{
"Rows": {
},
"type": "Section",
"group": "Income",
"Summary": {
"ColData": [
{
"value": "Total Income"
},
{
"value": "325.00"
}
]
}
},
{
}
]
}
}

For the specific JSON sample that you have given in your question, you can extract the 325.00 value using SelectToken like this:
var obj = JObject.Parse(json);
var amount = (string)obj.SelectToken("Rows.Row[0].Summary.ColData[1].value");
Fiddle: https://dotnetfiddle.net/WRMAVu
If you want to extract both the label and the amount you can use SelectTokens instead with a wildcard for the ColData index:
var obj = JObject.Parse(json);
var values = obj.SelectTokens("Rows.Row[0].Summary.ColData[*].value")
.Select(t => (string)t)
.ToArray();
Fiddle: https://dotnetfiddle.net/DHZhS2

Related

Reformatting a JSON in C#

I have a JSON response here,
{
"Items": [
{
"Key": {
"timestamp": "2022-11-06T20",
"value": 100.80
}
},
{
"Key": {
"timestamp": "2022-11-07T08",
"value": 100.90
}
}
]
}
That I would like to reformat to this:
{
"Key": [
{
"timestamp": "2019-01-08T20",
"value": 12.44
},
{
"timestamp": "2018-12-12 16:23:00",
"value": 12.45
}
]
}
For all responses, the Key must only be on the top once followed by an array of timestamps and values, and remove the Items parent value completely. I have tried doing this and messing around with the implementation, but I keep receiving multiple different errors. Is this the correct idea to do it or is there a better way to implement this?
JObject obj = JObject.Parse(jsonOutput);
JObject newObj = new JObject();
new JProperty("KEY", new JArray(
.Children<JProperty>()
.Select(j => new JObject(
new JProperty("timestamp", j.Value["timestamp"]),
new JProperty("value", j.Value["value"])
)
)
)
);
jsonOutput = newObj.ToString();
What is the correct way to implement this idea? Thanks!
This can be done very easily by combining
SelectTokens() with a JSONPath wildcard operator for the Items[*] array to select all required JSON objects.
Serialization of an anonymous type object to create the required output structure.
Thus:
var query = obj.SelectTokens("Items[*].Key");
jsonOutput = JsonConvert.SerializeObject(new { Key = query }, Formatting.Indented);
Demo fiddle here.
you can fixed it in one line
jsonOutput = new JObject {new JProperty("Key", ((JArray)JObject.Parse(jsonOutput)
["Items"]).Select(s => s["Key"]))}.ToString();

Filtering or removing array objects from the DTO class object based on an another list in .net

I have below code :
[
{
"OrderId": "Order1",
"filterOrder": [ "ABC", "XYZ" ],
"Details": [
{
"id": 1,
"value": 100,
"filterDetails": [ "Apples", "Oranges" ]
},
{
"id": 2,
"value": 200,
"filterDetails": [ "Banana", "Blank" ]
}
]
},
{
"OrderId": "Order2",
"filterOrder": [ "PQR", "Blank" ],
"Details": [
{
"id": 1,
"value": 100,
"filterDetails": [ "Apples", "Peaches" ]
},
{
"id": 2,
"value": 200,
"filterDetails": [ "Banana", "Mango" ]
}
]
}
]
C# code:
string i = GetJsonText();
var lst = JsonConvert.DeserializeObject<List<Root>>(i);
My requirement here is to remove all those objects from the response where the filters are mentioned as "Blank".
So I have used the below code to remove the blanks :
lst.RemoveAll(x => x.filterOrder.Contains("Blank"));
lst.ForEach(fe => {fe.Details.RemoveAll(r=> r.filterDetails.Contains("Blank"));});
This is working perfectly fine. But now the requirement changed to remove objects based on multiple strings and not single string. Means I'll have something like
string removeCriteria ="Blank,Blank1,Blank2"
I convert this into a list of strings like this :
List<String> removeList = removeCriteria.Split(",").ToList();
Now I have use removeList in the above code instead of hardcoded "Blank". What can I try to resolve this?
No sure if I am missing something here but isn't this a fairly simple ForEeach loop?
string removeCriteria ="Blank,Blank1,Blank2"
List<String> removeList = removeCriteria.Split(",").ToList();
ForEach (String toRemove in removeList)
{
lst.RemoveAll(x => x.filterOrder.Contains(toRemove));
lst.ForEach(fe => {fe.Details.RemoveAll(r=>r.filterDetails.Contains(toRemove));});
}
For a little better performance, especialy if each parent has alot of child records, I would suggest to change MattBaran answer a little
string removeCriteria ="Blank,Blank1,Blank2"
List<String> removeList = removeCriteria.Split(",").ToList();
//at first remove all parents with children
foreach (var toRemove in removeList)
{
lst.RemoveAll(x => x.filterOrder.Contains(toRemove));
}
//after this check the children of remaining records
foreach (var toRemove in removeList)
{
lst.ForEach(fe => {fe.Details.RemoveAll (r=>r.filterDetails.Contains (toRemove));});
}

Transform a JSON object to a JSON array, taking the first level of properties

I've this JSON object
{
"08f4f705-6e14-4781-8241-d04bf2dc6ada": {
"description": "xxxxxxxx",
"note": "yyyyyyyy"
},
"05f4f995-6e14-4567-8241-d04bf2d456ee": {
"description": "aaaaaa",
"note": "bbb"
},
"0675f995-6e14-4567-8241-d4567f2d456z": {
"description": "fffff",
"note": "gggg"
}
}
I need to convert into a JSON array like this:
(the elements should be the content of the first level properties)
[
{
"description": "xxxxxxxx",
"note": "yyyyyyyy"
},
{
"description": "aaaaaa",
"note": "bbb"
},
{
"description": "fffff",
"note": "gggg"
}
]
I can't manipulate the object and I didn't find an appropriate resource to follow. How can I do it?
You can achieve this by deserializing your json string into Dictionary<string, object>:
var obj = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
After that you extract the values and serialize them back to json:
var newJson = JsonConvert.SerializeObject(obj.Values);

Search By Partial word of a sentence in elastic search

I am very new to Elastic Search , I want to search a result based on a partial word of a sentence , like the search string is
"val"
and it should search the result with string value
"value is grater than 100"
but if I am using a query
var searchDescriptor = new SearchDescriptor<ElasticsearchProject>()
searchDescriptor.Query(q =>
q.Wildcard(m => m.OnField(p => p.PNumber).Value(string.Format("*{0}*", searchString)))
);
it will work only for one word string like
"ValueIsGraterThan100"
if I use something like this
var searchDescriptor = new SearchDescriptor<ElasticsearchProject>()
searchDescriptor.Query(q =>
q.QueryString(m => m.OnFields(p => p.PName).Query(searchString))
);
This will work for entire word , like i have to provide search string as
"value"
to search
"value is grater than 100"
only providing val will not work.So how i can fulfill my requirement ?
Your field currently is not_analyzed, You can use edge n-gram analyzer made up of edge ngram filter to token your field before saving the fields on inverted index. You can use the following settings
PUT index_name1323
{
"settings": {
"analysis": {
"analyzer": {
"autocomplete_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"standard",
"lowercase",
"filter_edgengram"
]
}
},
"filter": {
"filter_edgengram": {
"type": "edgeNGram",
"min_gram": 2,
"max_gram": 15
}
}
}
},
"mappings": {
"test_type": {
"properties": {
"props": {
"type": "string",
"analyzer": "autocomplete_analyzer"
}
}
}
}
}
Now you can simply use both query_string or term filter to match both your documents to val
POST index_name1323/_search
{
"query": {
"query_string": {
"default_field": "props",
"query": "val"
}
}
}
Hope this helps

JSON nested array

Lets say i have the following JSON
{
"data": [
{
"from": {
"name": "aaa bbb",
},
"actions": [
{
"name": "Comment",
"link": "http://...
},
{
"name": "Like",
"link": "http://.."
}
],
},
And i have
JSONObject wallData = helper.Get("/me/feed");
if (wallData != null)
{
var data = wallData.Dictionary["data"];
List<JSONObject> wallPosts = data.Array.ToList<JSONObject>();
}
foreach (Facebook.JSONObject wallItem in wallPosts)
{ ... }
Which stores me whole feed into wallData and 'data' object into wallPosts.
So then i can access the wallItem.Dictionary["from"].Dictionary["name"], and i get "aaa bbb".
But i can't get inside the actions array
The wallItem.Dictionary["actions"].Dictionary["name"] doesn't work.
Any idea
You need to do something like wallItem.Dictionary["actions"][0].Dictionary["name"] because "actions" is an array.
On a different note...its neater if u directly into a class...like this
var jSerializer = new JavaScriptSerializer();
var jsonObject = jSerializer.Deserialize<DataObject>(json);
The DataObject will be a class which emulates ur JSON data in a strongly typed class. Depending on the size of ur Json you will not have to use a lot of strings in your code.

Categories

Resources