Filter parsed JSON object - c#

I am making rest call and receving following JSON response:
{
"issues": [{
"id": "250271",
"self": "KeyUrl1",
"key": "Key-8622",
"fields": {
"attachment": [{
"self": "AttachmentUrl1",
"id": "106198",
"filename": "export.htm"
}
],
"customfield_11041": "Test"
}
},
{
"id": "250272",
"self": "KeyUrl2",
"key": "Key-8621",
"fields": {
"attachment": [{
"self": "AttachmentUrl2",
"id": "106199",
"filename": "lmn.htm"
}
],
"customfield_11041": "Test"
}
},
]
}
I parsed it using NewtonSoft Json to JObject.
var jObject = JObject.Parse(response);
Further I am trying to filter such records where either attachment is missing or none of the attachments contain filename like "export".
Following is the code I have written, ideally it should result in just 1 record in the records object, however its returning both the objects.
var issues = jObject["issues"] as JArray;
var records = issues.Where(x => !x["fields"]["attachment"].Any() || !x["fields"]["attachment"].Any(y => y["filename"].Contains("export")));
Need help to figure out whats going wrong.
Here's fiddle link - https://dotnetfiddle.net/AVyIHr

The problem is that you're calling Contains("export") on the result of y["filename"], which isn't a string - it's a JToken. You need to convert to a string first, to use the form of Contains that you're expecting.
Additionally, you can get rid of the first condition - an issue with no attachments doesn't have any attachments with "export" filename anyway.
That leaves this:
var records = issues
.Where(x => !x["fields"]["attachment"].Any(y => ((string) y["filename"]).Contains("export")))
.ToList();
You may well find it's simpler to deserialize to a class, however - that will reduce the risk of typos and the risk of this sort of conversion error. If you deserialized to a List<Issue> you'd have a condition of:
x => !x.Fields.Attachments.Any(y => y.Filename.Contains("export"))
... which I think is rather cleaner.

var records = issues.Where(x => !x["fields"]["attachment"].Any() || !x["fields"]["attachment"].Any(y => y["filename"].ToString().Contains("export"))).ToList();
Add .ToString() will resolve the issue.

Related

JSON extract date from matching string

I am entirely new to JSON, and haven't got any familiarity with it at all. I'm tinkering around with some JSON data extracts to get a feel for it.
Currently, I have a chat export which has a large number of keys. Within these keys are a "date" key, and a "from_id" key.
I would like to search a JSON file for a matching value on the "from_id" key, and return all the values against the "date" keys with a matching "from_id" value.
For example:
{
"name": "FooBar Chat Group",
"type": "textchat",
"id": 123456789,
"messages": [
{
{
"id": 252930,
"type": "message",
"date": "2021-03-03T01:39:30",
"date_unixtime": "1614735570",
"from": "Person1",
"from_id": "user1234",
"text": "This is a message!"
},
{
"id": 252931,
"type": "message",
"date": "2021-03-03T01:41:03",
"date_unixtime": "1614735663",
"from": "Person2",
"from_id": "user9876",
"text": "This is a reply!"
},
{
"id": 252932,
"type": "message",
"date": "2021-03-03T01:42:01",
"date_unixtime": "1614735721",
"from": "Person2",
"from_id": "user9876",
"text": "This is some other text!"
},
{
"id": 252933,
"type": "message",
"date": "2021-03-03T01:42:44",
"date_unixtime": "1614735764",
"from": "Person1",
"from_id": "user1234",
"text": "Yeah, indeed it is!"
}
]
}
I want to search from_id "user1234", and for it to return the following:
2021-03-03T01:39:30
2021-03-03T01:42:44
These are the two dates that have a matching from_id.
How would I go about doing something like this, please?
I am entirely new to this, so a super basic explanation with resources would really be appreciated. Thanks!
you can try this c# code. At first you have to parse your json strig to create an object from string. Then you can use LINQ to get the data you need
using Newtonsoft.Json;
JArray messages = (JArray) JObject.Parse(json)["messages"];
string from_id="user1234";
DateTime[] dates = messages
.Where(m=> (string) m["from_id"] ==from_id)
.Select(m => (DateTime) m["date"])
.ToArray();
Assuming your sample is part of a JSON Array - starts with [ and ends with ] - you should be able to iterate and conditionally select what you want.
In javascript, you can use a for of to iterate through and an if to match your request:
for(let item of array){
if(item['from_id'] == 'user1234')
console.log(item.date);
}
As we don't know the language you're actually using, a more wide code version of it could be something like:
for(let i=0;i < array.length; i++){
if(array[i]['from_id'] == 'user1234'){
print(array[i]['date']);
}
}

Write a JsonPath query for a null property with Newtonsoft Json.NET

Given a JSON array of:
[
{
"id": 1,
"name": "abc"
},
{
"id": 2
},
{
"id": 3,
"name": "def"
}
]
I would expect:
JArray jArray = JArray.Parse(json);
dynamic value = jArray.SelectTokens("$[?(#['name'] == null || #['name'] == 'abc')]");
to produce:
[
{
"id": 1,
"name": "abc"
},
{
"id": 2
}
]
This tests correctly using a variety of online JsonPath testers. But when I run it with Json.NET, I am getting:
[
{
"id": 1,
"name": "abc"
}
]
Is it possible for me to change the JsonPath to handle this? Is it the null in the query that is the problem?
For clarity, I need to use JsonPath because it is stored in a configuration file and applied dynamically.
I expect that Newtsoft is considering absence to be different from "present with a null value," whereas the others you've tried consider them to be the same.
I imagine if you update the path to
$[?(!#['name'] || #['name'] == null || #['name'] == 'abc')]
it might work for you.
Alternatively, updating the data to
[
{
"id": 1,
"name": "abc"
},
{
"id": 2,
"name": null
},
{
"id": 3,
"name": "def"
}
]
would also yield the middle item.
We haven't defined this yet in the specification effort, but it's a good one. I'll raise that in an issue.
You can also see there's no consensus among libraries with this test.
With LINQ to JSON you can solve the same problem like this:
var json = File.ReadAllText("sample.json");
var semiParsedJson = JArray.Parse(json);
var filteredJson = from item in semiParsedJson
let name = (string)item["name"]
where name == null || name == "abc"
select item;
Console.WriteLine(new JArray(filteredJson));
The output will be as expected:
[
{
"id": 1,
"name": "abc"
},
{
"id": 2
}
]

Extract first set of records in JSON C#

I have a requirement to get the first set of records in c# JSON. Here is my JSON data for example
string sJSON = "{
{
"ID": "1",
"Name":"John",
"Area": "Java" ,
"ID": "2",
"Name": "Matt",
"Area": "Oracle" ,
"ID": "3","Name":
"Danny","Area": "Android"
}
}"
I need to extract only the 1st set of records (i.e. {{"ID": "1", "Name":"John", "Area": "Java"}}).
If there is only one record my code (see below) works fine but when there are multiple records it takes the last set of JSON data (i.e. {{"ID": "3","Name": "Danny","Area": "Android"}}).
JObject jsonObject = JObject.Parse(sJSON);
string sID = (string)jsonObject["ID"];
string sName = (string)jsonObject["Name"];
string sArea = (string)jsonObject["Area"];
Can anyone help me extract only the 1st set of JSON data?
You return the JSON data as JSON Array, now it is a simple JSON string.
If you're able to generate like below then you can easily get the single JSON element easily.
[{ "ID": "1", "Name":"John", "Area": "Java" },{ "ID": "2","Name": "Matt","Area": "Oracle" },{ "ID": "3","Name": "Danny","Area": "Android" } ]
Use the below link, to understand this JSON format.
http://json.parser.online.fr/
Parse the data as JToken.
Such that you have something like:
var jToken = JToken.Parse(sJSON);
var isEnumerable = jToken.IsEnumerable()
if(isEnumeable)
{
cast as JArray and get firstOrdefault
}
var isObject = jToken.IsObject();
if(isObject )
{
cast as JObject and perform straight casting
}

Json Object parse error

I am storing data in my cassandra database as string and i want to retrieve the string and convert it into json. i get an exception saying
An unhandled exception of type 'Newtonsoft.Json.JsonReaderException' happened
is there something wrong with the data stored ? or i am doing some other thing wrong ?
My query is :
INSERT INTO table2(key1,col1) values ('5',{'url':'{"hello":
{"hi":{"hey":"1","time":"5"}},
{"reg":{"hey":"1","time":"1"}},
{"install":{"hey":"0"}}},
"task":"1","retry":"00",
"max":"5","call":"140"'});
In my db when i click the map<text,text> column, it gets stored as :
{\"hello\":\r\n
{\"subscription_atrisk\":{\"hey\":\"1\",\"time\":\"100\"}},
{\"reg\":{\"hey\":\"1\",\"time\":\"2000\"}},
\"task\":\"0\",\"retry\":\"300\",\"max\":\"5\",\"call\":\"14400\"}
in my c# code, i try
string s = "{\"hello\":\r\n {\"subscription_atrisk\":{\"hey\":\"1\",\"time\":\"100\"}},{\"reg\":{\"hey\":\"1\",\"time\":\"2000\"}},\"task\":\"0\",\"retry\":\"300\",\"max\":\"5\",\"call\":\"14400\"";
Jobject json = Jobject.Parse(s); //Get an Error here.
Could anyone please throw some light on this ?
In JSON, an object should contain a key and either a value or another object/array.
You have syntax errors in your JSON object. First of all, always use double quotes.
Then... The url object has a key Hello but then where you are supposed to place two more keys, you're just putting there two more objects, as if it was an array.
This could be a correct syntax:
{
"url": {
"hello": {
"hi": {
"hey": "1",
"time": "5"
}
},
"MissingKey1":{
"reg": {
"hey": "1",
"time": "1"
}
},
"MissingKey2":{
"install": {
"hey": "0"
}
}
},
"task": "1",
"retry": "00",
"max": "5",
"call": "140"
}
Or if you really meant to have a hello object and an array of two more objects inside url:
{
"url": {
"hello": {
"hi": {
"hey": "1",
"time": "5"
}
},
"AnArray": [{
"reg": {
"hey": "1",
"time": "1"
}
}, {
"install": {
"hey": "0"
}
}]
},
"task": "1",
"retry": "00",
"max": "5",
"call": "140"
}
I suggest that before you store those JSON objects in the database, ALWAYS validate them to make sure that they're valid of syntax.
Or even better: this Newtonsoft library provides functions which serializes(creates) JSON strings from other objects. See JsonConvert.SerializeObject Method
In general it is a good idea to look around in the API documentation, it really can save you a lot of time so that you don't have to do unnecessary work.
Looks like you're missing a closing }
Try:
string s = "{\"hello\": {\"subscription_atrisk\":{\"hey\":\"1\",\"time\":\"100\"}}, \"missing_key\": {\"reg\":{\"hey\":\"1\",\"time\":\"2000\"}},\"task\":\"0\",\"retry\":\"300\",\"max\":\"5\",\"call\":\"14400\"}";

Read Foursquare Json Response with JSON.NET

I am trying to access all the categories in the first level within a Foursquare response:-
{
"meta": {
"code": 200
},
"response": {
"categories": [{
"id": "4d4b7104d754a06370d81259",
"name": "Arts & Entertainment",
"pluralName": "Arts & Entertainment",
"shortName": "Arts & Entertainment",
"icon": {
"prefix": "https:\/\/foursquare.com\/img\/categories\/arts_entertainment\/default_",
"sizes": [32, 44, 64, 88, 256],
"name": ".png"
},
"categories": [{
"id": "4bf58dd8d48988d1e1931735"
using JSON.NET:-
JObject o = JObject.Parse(FoursquareObject.GetCategories());
IList<string> categories = o.SelectToken("categories[0]").Select(s => (string)s).ToList();
Where FoursquareObject.GetCategories() returns the response as a string. I also tried:-
JArray categories = (JArray)o["categories"];
var categories = (string) o["response[0].categories"];
...and numerous variations of, just to see the response in the variable and always get 'Object reference' or 'cannot be {null}' errors. I know I'm close, but for the life of me can't work out how to get at the 'categories' part of the response...
Can anyone point me in the right direction?
Help is appreciated. ;)
UPDATE:
Thanks to the answers from L.B and Meklarian, I added this code (and variants of):-
dynamic four = JsonConvert.DeserializeObject(FoursquareObject.GetCategories());
foreach (var cat in four)
{
context.Response.Write(cat.response.categories.id);
}
But regardless of what I try in the Write(), I always get:-
'Newtonsoft.Json.Linq.JProperty' does not contain a definition for
'response'
I tried loads of combinations, no-luck. I checked the output from the JSON file, I get pure JSON response as a string. Just a note, that categories can exist in categories, hence why the JSON seems to look broken. I assure you it's not. I'm completely stuck!
There are multiple ways to parse this; but in the style you've initially presented, you should try accessing it with [] indexers.
Note that your data has a root object with two properties, meta and response. Assuming response can't be null, you can access categories from it directly like this:
var root = JObject.Parse(/* your json string here */);
var categories = root["response"]["categories"];
var firstCategory = categories[0];
Note that you can use strings matching property names to descend into nested levels, and integers to index into arrays in scope.
Here is the rest of a sample program that can parse the json snippet you've provided.
using System.Windows.Forms;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
namespace _4sqCatResponse
{
class Program
{
[STAThread]
static void Main(string[] args)
{
OpenFileDialog dlg = new OpenFileDialog();
if(dlg.ShowDialog() != DialogResult.OK){return;}
string json = System.IO.File.ReadAllText(dlg.FileName);
var root = JObject.Parse(json);
var categories = root["response"]["categories"];
var firstCategory = categories[0];
Console.WriteLine("id: {0}", firstCategory["id"]);
Console.WriteLine("name: {0}", firstCategory["name"]);
Console.WriteLine("pluralName: {0}", firstCategory["pluralName"]);
Console.WriteLine("shortName: {0}", firstCategory["shortName"]);
var icon = firstCategory["icon"];
Console.WriteLine("icon.prefix: {0}", icon["prefix"]);
Console.WriteLine("icon.sizes[0]: {0}", icon["sizes"][0]);
Console.WriteLine("icon.name: {0}", icon["name"]);
Console.ReadKey();
}
}
}
Also I'm a little confused by your json sample; I think you may have overlaid part of your sample or cut something out as you have categories nested in categories. If there is indeed a 2nd level categories inside your categories element and that's what you want, you can access it with this:
var categories2 = root["response"]["categories"][0]["categories"][0];
Console.WriteLine("inner categories id: {0}", categories2["id"]);
Here is the json source I used to test, copied from yours but with closing } and ] marks where needed to make it parse.
{
"meta": {
"code": 200
},
"response": {
"categories": [{
"id": "4d4b7104d754a06370d81259",
"name": "Arts & Entertainment",
"pluralName": "Arts & Entertainment",
"shortName": "Arts & Entertainment",
"icon": {
"prefix": "https:\/\/foursquare.com\/img\/categories\/arts_entertainment\/default_",
"sizes": [32, 44, 64, 88, 256],
"name": ".png"
},
"categories": [{
"id": "4bf58dd8d48988d1e1931735"
}]
}]
}
}
I think this should work
dynamic four2 = JsonConvert.DeserializeObject(FoursquareObject.GetCategories());
foreach(var cat in four2.response.categories)
{
Console.WriteLine(cat.id + " " + cat.name + " " + cat.icon.prefix);
}
Use http://json2csharp.com/ to generate C# classes, use RootObject and then access the individual venues

Categories

Resources