JSON extract date from matching string - c#

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

Related

Select type object from json?

I have a problem with correct parse object from json query. I read something about JObject. Now i have two Model for example like Car and MotorBike. Query result is:
"Vehicles":
[
{
"Id": 1,
"title": "test",
"price": "4000",
"type": "Car"
},
{
"Id": 1,
"title": "test",
"price": "4000",
"drivingLicenseCat" "A",
"type": "MotorBike"
}
]
how can i parse to custom model by type
How much control over the JSON do you have? If you are generating the JSON out of, say, web api correctly, it would come through more like:
"Vehicles":
[
{
"Id": 1,
"title": "test",
"price": "4000",
"$type": "YourNamespace.Car, YourNamespace"
},
{
"Id": 1,
"title": "test",
"price": "4000",
"drivingLicenseCat" "A",
"$type": "YourNamespace.MotorBike, YourNamespace"
}
]
and then it would be automatically deserialized when you bring it in...
Ensure, in the model that you are serializing and sending out as JSON, that you mark it up like so:
[JsonProperty(ItemTypeNameHandling = TypeNameHandling.All)]
This will add the type names to the objects as they are serialized. I should also note, that this is with Newtonsoft as your Json library. I'm not sure about the built-in Json.

Azure Search - Accent insensitive analyzer not working when sorting

I'm using Azure Search. I have a model with a property with this attributes
[IsRetrievable(true), IsSearchable, IsSortable, Analyzer("standardasciifolding.lucene")]
public string Title { get; set; }
I want the search to be accent insensitive. Although it is working when searching/filtering, it is not working when sorting the results. So, If I have words that start with an accent and I sort alphabetically, those results appear at the end of the list.
I verified your use case by creating an index with Id and a Title field that uses the standardasciifolding.lucene analyzer. I then submitted the 4 sample records via the REST API:
{
"value": [
{
"#search.action": "mergeOrUpload",
"Id": "1",
"Title" : "øks"
},
{
"#search.action": "mergeOrUpload",
"Id": "2",
"Title": "aks"
},
{
"#search.action": "mergeOrUpload",
"Id": "3",
"Title": "áks"
},
{
"#search.action": "mergeOrUpload",
"Id": "4",
"Title": "oks"
}
]}
I then ran a query with $orderby specified. I used Postman with variables wrapped in double curly braces. Replace with relevant values for your environment.
https://{{SEARCH_SVC}}.{{DNS_SUFFIX}}/indexes/{{INDEX_NAME}}/docs?search=*&$count=true&$select=Id,Title&searchMode=all&queryType=full&api-version={{API-VERSION}}&$orderby=Title asc
The results were returned as
{
"#odata.context": "https://<my-search-service>.search.windows.net/indexes('dg-test-65224345')/$metadata#docs(*)",
"#odata.count": 4,
"value": [
{
"#search.score": 1.0,
"Id": "2",
"Title": "aks"
},
{
"#search.score": 1.0,
"Id": "4",
"Title": "oks"
},
{
"#search.score": 1.0,
"Id": "3",
"Title": "áks"
},
{
"#search.score": 1.0,
"Id": "1",
"Title": "øks"
}
]
}
So, the sort order is indeed a, o, á, ø which confirms what you find. The order is inversed if I change to $orderby=Title desc. Thus, the sorting appears to be done by the original value and not the normalized value. We can check how the analyzer works, by posting a sample title to the analyzer with a POST request to
https://{{SEARCH_SVC}}.{{DNS_SUFFIX}}/indexes/{{INDEX_NAME}}/docs?search=*&$count=true&$select=Id,Title&searchMode=all&queryType=full&api-version={{API-VERSION}}&$orderby=Title asc
{ "text": "øks", "analyzer": "standardasciifolding.lucene" }
Which produces the following tokens
{
"#odata.context": "https://<my-search-service>.search.windows.net/$metadata#Microsoft.Azure.Search.V2020_06_30_Preview.AnalyzeResult",
"tokens": [
{
"token": "oks",
"startOffset": 0,
"endOffset": 3,
"position": 0
},
{
"token": "øks",
"startOffset": 0,
"endOffset": 3,
"position": 0
}
]
}
You could try to define a custom analyzer which produces a normalized version, but I am not sure it will work. For example, the sorting does not appear to support case-insensitive sorting which would be related to this use case where multiple characters should be sorted as if they were a normalized version. E.g. a and A cannot be sorted as the same character according to this user voice entry (feel free to vote for it).
WORKAROUND
The best workaround I can think of is to process the data yourself. Let Title contain the original title, and then create another field called TitleNormalized where you store the normalized version. In your application you would then query with $orderby on the TitleNormalized field.
There is a new feature that allows you to enable normalization while filtering. Please check out the Text normalization for case-insensitive filtering, faceting and sorting feature that's in Preview.
You can update your index to use this "normalizer" feature for the fields in which you'd like case-insensitive order-by operations.
You don't need a separate field TitleNormalized anymore. You can add "normalizer": "standard" to the Title field, and $orderBy=Title will sort in the order you'd like, ignoring casing and accents.
The "standard" normalizer is pre-defined. If you'd like other filters to be applied, please look at predefined and custom normalizers
"index": {
"name": "your-name-here",
"fields": [
{"name": "Title", "type": "Edm.String", "filterable": true, "sortable": true, "facetable": false, "searchable": true, "normalizer":"standard"}
]
}

Filter parsed JSON object

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.

Wildcard value in JSONPath

I have the below JSON that I am trying to interpret, using json.net.
{
"platformUpdateDomain": 0,
"platformFaultDomain": 0,
"vmAgent": {
"vmAgentVersion": "2.5.1198.709",
"statuses": [
{
"code": "ProvisioningState/succeeded",
"level": "Info",
"displayStatus": "Ready",
"message": "GuestAgent is running and accepting new configurations.",
"time": "2015-04-21T11:42:44-07:00"
}
]
},
"disks": [
{
"name": "myosdisk",
"statuses": [
{
"code": "ProvisioningState/succeeded",
"level": "Info",
"displayStatus": "Provisioning succeeded",
"time": "2015-04-10T12:44:10.4562812-07:00"
}
]
}
],
"statuses": [
{
"code": "ProvisioningState/succeeded",
"level": "Info",
"displayStatus": "Provisioning succeeded",
"time": "2015-04-10T12:50:09.0031588-07:00"
},
{
"code": "PowerState/running",
"level": "Info",
"displayStatus": "VM running"
}
]
}
I wish to extract the Status, where the code contains the below value:
PowerState
However, I cannot work out how to do this, I can match against the entire string using Json.Net, but I'd like to
myJsonJObject.SelectToken("$.statuses[?(#.code == 'PowerState/running')]");
However, part of the "code" value can change, so I'd like to try and search based on the below condition
myJsonJObject.SelectToken("$.statuses[?(#.code == 'PowerState/*')]");
What is the correct Jsonpath expression to do this? Matching against a substring would also work, but again, I cannot find an example to do this.
Workaround is to use linq.
select all the status objects, filter on the code value, which has been converted to a string to use the contains method.
var x = myJsonJObject.SelectToken("$.statuses").Where(y => ((string)y.SelectToken("$.code")).Contains("PowerState"));

Parsing JSON in C#

I have a JSON string that I am sending to a c# server. It comprises an array of Event objects and an Array of relationship objects. The relationship objects describe the database table relationships.
However I'm having trouble getting data from the the JSON at the server. The object doesn't exist on the server to deserailize into and JSON.net throws parse errors when I try the following:
// Both throw parse errors
JObject o = JObject.Parse(Request.Form.ToString());
JsonConvert.DeserializeObject<MobileEvents>(Request.Form.ToString());
the JSON:
{
"CreateEvents": {
"Event": [
{
"Id": "1",
"Subject": "Hire a Clown"
}
],
"Relationship": [
{
"Primary": "Table1",
"Secondary": "Table2",
"Field": [
{
"Table1Id": "1",
"Table2Id": [
"101"
]
}
]
},
{
"Primary": "Table1",
"Secondary": "Table3",
"Field": [
{
"Table1Id": "1",
"Table3Id": [
"200025"
]
}
]
},
{
"Primary": "Table1",
"Secondary": "Table4",
"Field": [
{
"Table1Id": "1",
"Table4Id": [
"3"
]
}
]
}
]
}
}
Request.Form.ToString() would returns the result like "a=1&b=3", it's definitely not what you need.
If you're passing values as submiting a form, you can use Request.Form["your-key"] to get the value.
If you're passing values by the http body, you can use new StreamReader(Request.InputStream).ReadToEnd() to get the whole JSON string.
I think you have an error within your getting ...
It's not
this.Request.Form.ToString(); // see http://stackoverflow.com/questions/7065979/why-is-the-return-value-of-request-form-tostring-different-from-the-result-of for output
Instead it should be
this.Request.Form["myInputNAME"].ToString();
Important - really use the name-attribute of your input/select/...-element
Anyways: I would like to encourage you, to use eg. <asp:HiddenField runat="server" ID="foo" />. When you have a server-control you can then access its value by simple doing this.foo.Value at server-side, whereas at client-side you can access the input field like document.getElementById('<%= this.foo.ClientID %>')

Categories

Resources