I want to parse JSON in this format
json result:{
"time": 23,
"npc":[
{
"id":1,
"b_box" {
"left": 250,
"top": 135,
},
},
{
"id":2,
"b_box" {
"left": 234,
"top": 343,
},
},
{
"id":3,
"b_box" {
"left": 342,
"right": 543,
}
}
]
}
Here is my code for parsing
void extractD (string jsonResult) {
JSONNode incomingData = SimpleJSON.JSON.Parse(jsonResult);
JSONArray npc = incomingData ["npc"].AsArray;
foreach (JSONNode bBox in npc) {
int bLeft = bBox ["b_box"]["left"];
int bTop = bBox ["b_box"]["top"];
}
I want to initialize variables with the left and top values for id:1 id:2 and id:3 separately how should I modify my code to accomplish this? Code examples would be much appreciated.
Related
I have a json file like this:
[
{
"key1": {
"find": 5,
"count": 65,
"name": "Parser"
},
"init": {
"key2": {
"find": 5,
"count": 15,
"name": "Some"
},
"arr": [
{
"key2": {
"find": 8,
"count": 32,
"name": "Object"
},
"temp": {
"pay": null
}
}
]
}
},
{
"key3": {
"find": 5,
"count": 23,
"name": "String"
},
"classes": [],
}
]
And I want to get list of all nodes that contains key "find" and value "5". The result have to be:
{
"find": 5,
"count": 65,
"name": "Parser"
},
{
"find": 5,
"count": 15,
"name": "Some"
},
{
"find": 5,
"count": 23,
"name": "String"
}
The difficulty is that the nesting can be any, but I need to get only those nodes that contain key "find" and the value "5" for it. How can I go through the entire file and get the nodes I need?
You can use JToken for this purpose, use the below function to find the nodes.
public void FindNodes(JToken json, string name, string value, List<JToken> nodes)
{
if (json.Type == JTokenType.Object)
{
foreach (JProperty child in json.Children<JProperty>())
{
if (child.Name == name && child.Value.ToString() == value)
{
nodes.Add(child);
}
FindNodes(child.Value, name, value, nodes);
}
}
else if (json.Type == JTokenType.Array)
{
foreach (JToken child in json.Children())
{
FindNodes(child, name, value, nodes);
}
}
}
Use the method in this way,
var json = JsonConvert.DeserializeObject<JToken>(jsonString);
var nodes = new List<JToken>();
FindNodes(json, "find", "5", nodes);
I have two JSON objects -
json1 = {
"payload": {
"firstName": "John",
"lastName": "Doe",
"code": "test1",
"arrayProp1": [1, 2, 3],
"arrayProp2": [{
"prop1": "value1",
"prop2": "value2"
},
{
"prop1": "2_value1",
"prop2": "2_value2"
}
]
}
}
json2 = {
"payload": {
"code": "newCode",
"arrayProp1": [3,4],
"arrayProp2": [{
"prop1": "newValue1",
"prop2": "newValue2"
}
]
}
}
If I use the built-in merge (json1.Merge(json2)) the result obtained is -
result : {
"payload": {
"firstName": "John",
"lastName": "Doe",
"code": "newCode",
"arrayProp1": [1, 2, 3, 3, 4],
"arrayProp2": [{
"prop1": "value1",
"prop2": "value2"
},
{
"prop1": "newValue1",
"prop2": "newValue2"
},
{
"prop1": "2_value1",
"prop2": "2_value2"
}
]
}
}
Expected result -
{
"payload": {
"firstName": "John",
"lastName": "Doe",
"code": "newCode",
"arrayProp1": [3, 4],
"arrayProp2": [{
"prop1": "newValue1",
"prop2": "newValue2"
}]
}
}
I want to replace the parent property values of json1 based on values provided in json2.
I tried to write a function and this is the current version I have -
string Merge(string req1, string req2) {
try
{
JObject json1 = JObject.Parse(req1);
JObject json2 = JObject.Parse(req2);
foreach (var a in json2.DescendantsAndSelf())
{
if (a is JObject obj)
{
foreach (var prop in obj.Properties())
{
if(json1.SelectTokens(prop.Path).Any())
{
json1[prop.Path] = prop.Value;
}
}
}
}
req1 = json1.ToString();
}
catch(Exception ex)
{
//do nothing
}
return req1; }
There are 2 problems here -
"payload" is identified as property and json1 is replaced fully by json2 because of which I lose some of its properties.
After being replaced, when the loop continues to run, say property 'code' is to be updated, then the property path is payload.code, so on the line json1[prop.path] = prop.Value, instead of updating the existing code in the payload, it creates a new property called payload.code with value "newcode"
The final result of the code above is -
{
"payload": {
"code": "newCode",
"arrayProp1": [3, 4],
"arrayProp2": [{
"prop1": "newValue1",
"prop2": "newValue2"
}],
"payload.code": "newCode",
"payload.arrayProp1": [3, 4],
"payload.arrayProp2": [{
"prop1": "newValue1",
"prop2": "newValue2"
}],
"payload.arrayProp1[0].prop1": "newValue1",
"payload.arrayProp1[0].prop2": "newValue2"
}
}
Can someone please help me with this?
Your requirement is that array contents are replaced rather than concatenated when merging two JSON objects with JContainer.Merge(). You can achieve this via the JsonMergeSettings.MergeArrayHandling setting, which has the following values:
Concat 0 Concatenate arrays.
Union 1 Union arrays, skipping items that already exist.
Replace 2 Replace all array items.
Merge 3 Merge array items together, matched by index.
Specifically MergeArrayHandling.Replace will work as required:
json1.Merge(json2, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Replace
});
Demo fiddle here.
I created an elastic search index and the result of a simple search looks like:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 11,
"max_score": 1,
"hits": [
{
"_index": "shop-bestellung",
"_type": "bestellung",
"_id": "dc144b04-8e73-4ea5-9f73-95c01768fd26",
"_score": 1,
"_source": {
"id": "dc144b04-8e73-4ea5-9f73-95c01768fd26",
"bestellnummer": "B-20170302-026",
"shopid": "0143d767-8986-432a-a15d-00e1c4862b24",
"shopname": "DeeDa",
"erstelltVon": "5663bb4b-fc44-46ca-b875-a3487b588b24",
"bestellername": "Max Mann",
"bestelldatum": "2017-01-30T23:00:00Z",
"bestellpositionen": []
}
}
]
}
}
I tried to create a filter which should consits of following three restrictions:
Query text
Date range
Filter on a specific field: "erstelltVon"
My filter only consits of query text and date range:
{
"query":{
"query_string":{
"fields":[
"bestellnummer",
"bestellername",
"bestelldatum",
"erstelltVon",
"bestellpositionen.artikelname",
"bestellpositionen.artikelnummer",
"bestellpositionen.referenznummer"
],
"query":"*"
}
},
"filter": {
"range" : {
"bestelldatum" : {
"gte": "2017-02-04T23:00:00Z",
"lte": "now",
"time_zone": "+01:00"
}
}
}
}
I would like to add the third filter:
"erstelltVon": "5663bb4b-fc44-46ca-b875-a3487b588b24"
How can I do that?
You need to use a boolean filter.
Here is how to use it:
"filter": {
"bool" : {
"must": [
// FIRST FILTER
{
"range" : {
"bestelldatum" : {
"gte": "2017-02-04T23:00:00Z",
"lte": "now",
"time_zone": "+01:00"
}
}
},
{
// YOUR OTHER FILTER HERE
}
]
}
change "must" to "should" if you want to use a OR instead of an AND.
I have 2 json files, or String and i want to merge them based on ID. Like join on sql. This is the example:
This is Json 1:
{
"City": [{
"CityId": 9,
"CityName": "Kukes"
}, {
"CityId": 18,
"CityName": "Tirana"
}, {
"CityId": 19,
"CityName": "Vlore"
}, {
"CityId": 22,
"CityName": "temp"
}]
}
And this i json 2:
{
"Citizen": [{
"CitizenId": 38,
"CitizenLastName": "Bale",
"CitizenName": "Christian",
"City_Id": 19
}, {
"CitizenId": 39,
"CitizenLastName": "ttrtrt",
"CitizenName": "test",
"City_Id": 18
}, {
"CitizenId": 42,
"CitizenLastName": "Freeman",
"CitizenName": "Morgan",
"City_Id": 9
}, {
"CitizenId": 43,
"CitizenLastName": "Snow",
"CitizenName": "Jon",
"City_Id": 9
}, {
"CitizenId": 44,
"CitizenLastName": "test2",
"CitizenName": "test",
"City_Id": 9
}]
}
I want it to merge in a json file or string based on id like this structure:
{
"City":
[
{
"CityId":9,
"CityName":"Kukes",
"Citizens" : [{"CitizenId":42,"CitizenLastName":"Freeman","CitizenName":"Morgan","City_Id":9},{"CitizenId":43,"CitizenLastName":"Snow","CitizenName":"Jon","City_Id":9},{"CitizenId":44,"CitizenLastName":"test2","CitizenName":"test","City_Id":9}]
},
{
"CityId":18,
"CityName":"Tirana",
"Citizens" : [{"CitizenId":39,"CitizenLastName":"ttrtrt","CitizenName":"test","City_Id":18}]
},
{
"CityId":19,
"CityName":"Vlore",
"Citizens" : [{"CitizenId":38,"CitizenLastName":"Bale","CitizenName":"Christian","City_Id":19}]
},
{
"CityId":22,
"CityName":"temp",
"Citizens" : []
}
]
}
I've tried all day and still found nothing. Do you have any idea how to do this with Newtonsoft? Or any other way? But I'd like it with newtonsoft.
You can do this with LINQ to JSON, using ToLookup() to find all citizens for a given city:
var cities = JToken.Parse(cityJson);
var citizens = JToken.Parse(citizenJson);
var lookup = citizens.SelectTokens("Citizen[*]").ToLookup(c => (string)c["City_Id"]);
foreach (var city in cities.SelectTokens("City[*]"))
{
city["Citizens"] = new JArray(lookup[(string)city["CityId"]]);
}
Prototype fiddle.
To load your JSON from a file, then later save back, see Read JSON from a file and Write JSON to a file.
I have been searching here and I didn't find anything similar... However I apologize in advanced if it have escaped me, and I hope you can help out finding the correct direction.
I was looking for a way to implement the following in NEST C#:
"aggs": {
"sys_created_on_max": {
"max": {
"field": "sys_created_on"
}
},
"sys_created_on_min":{
"min": {
"field": "sys_created_on"
}
},
"sys_updated_on_max": {
"max": {
"field": "sys_updated_on"
}
},
"sys_updated_on_min":{
"min": {
"field": "sys_updated_on"
}
}
}
Meaning that I want to perform, in the same statement:
Max and Min aggregated value for "sys_created_on" field
and also
Max and Min aggregated value for "sys_updated_on" field
Thanks!
What you want is Stats Aggregation.
Here is an example input/output
INPUT
GET devdev/redemption/_search
{
"size": 0,
"aggs": {
"a1": {
"stats": {
"field": "reporting.campaign.endDate"
}
}
}
}
Result
{
"took": 97,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 146,
"max_score": 0,
"hits": []
},
"aggregations": {
"a1": {
"count": 11,
"min": 1443675599999,
"max": 1446353999999,
"avg": 1445607818180.818,
"sum": 15901685999989,
"min_as_string": "1443675599999",
"max_as_string": "1446353999999",
"avg_as_string": "1445607818180",
"sum_as_string": "15901685999989"
}
}
}
I've figured it out. In case of someone have the same doubt:
1) create a AggregationContainerDescriptor:
Func<AggregationContainerDescriptor<dynamic>, IAggregationContainer> aggregationsSelector = null;
2) Fill it up:
foreach (var field in requestList)
{
aggregationsSelector += ms => ms.Max(field.MaxAggregationAlias, mx => mx.Field(field.Name))
.Min(field.MinAggregationAlias, mx => mx.Field(field.Name));
}
3) Query it:
var esResponse = _esClient.Raw.Search<dynamic>(indexName.ToLower(), new PostData<dynamic>(jsonStr), null);
Cheers!