I have the following json structure that I am getting from an api:
{
"event_instance": [
{
"id": 55551244,
"event_id": 11112,
"name": "Brown Belt Karate Class",
"staff_members": [
{
"id": 12345,
"name": "John Smith"
}
],
"people": [
{
"id": 111,
"name": "Jane Doe"
},
{
"id": 222,
"name": "Josh Smith"
},
{
"id": 333,
"name": "Ben Johnson"
}
],
"visits": [
{
"id": 1234578,
"person_id": 111,
"state": "completed",
"status": "complete"
},
{
"id": 1239865,
"person_id": 222,
"state": "completed",
"status": "complete"
},
{
"id": 1239865,
"person_id": 333,
"state": "canceled",
"status": "cancel"
}
]
}
]
}
I am deserializing this into the following .net objects using JSON.NET:
[JsonObjectAttribute("event_instance")]
public class EventInstance
{
[JsonPropertyAttribute("id")]
public int Id { get; set; }
[JsonPropertyAttribute("event_id")]
public int EventId { get; set; }
[JsonPropertyAttribute("name")]
public string Name { get; set; }
[JsonPropertyAttribute("staff_members")]
public List<StaffMember> StaffMembers { get; set; }
[JsonPropertyAttribute("visits")]
public List<Visit> Visits { get; set; }
[JsonPropertyAttribute("people")]
public List<Student> Students { get; set; }
}
[JsonObjectAttribute("staff_members")]
public class StaffMember
{
[JsonPropertyAttribute("id")]
public int Id { get; set; }
[JsonPropertyAttribute("name")]
public string Name { get; set; }
}
[JsonObjectAttribute("people")]
public class People
{
[JsonPropertyAttribute("id")]
public int Id { get; set; }
[JsonPropertyAttribute("name")]
public string Name { get; set; }
}
[JsonObjectAttribute("visits")]
public class Visits
{
[JsonPropertyAttribute("id")]
public int Id { get; set; }
[JsonPropertyAttribute("person_id")]
public int PersonId { get; set; }
[JsonPropertyAttribute("state")]
public string State { get; set; }
[JsonPropertyAttribute("status")]
public string Status { get; set; }
}
I am using the following code to de-serialize:
var event = (EventInstance)JsonConvert.DeserializeObject(json, typeof(EventInstance));
The above works fine and gives me an accurate object representation of the above json structure. Now I am trying to query this event object to filter/project to a new structure that I can then serialize back to json and send down to the browser. I need to return a list of students for the event that are in a state of "completed" and a status of "complete". As you can see, the people array ties to the visits array (with id and person_id). I would like to produce the following simple output:
11112, Brown Belt Karate Class, John Smith, 111, Jane Doe
11112, Brown Belt Karate Class, John Smith, 222, Josh Smith
I have tried something like this:
var studentList = from theClass in event
from staff in theClass.StaffMembers
from student in theClass.People
from visits in theClass.Visits
where visits.Status == "complete"
&& visits.State == "completed"
select new
{
event_id = theClass.EventId
class_name = theClass.Name,
instructor_name = staff.Name,
student_id = student.Id,
student_name = student.Name
};
string _data = JsonConvert.SerializeObject(studentList);
Naturally this produces duplicate student names. I am new to linq. Basically I need to join/tie the people and visits array so I just get back a single student for that id, along with the root data for this event. Any advice on a better way to do this is much appreciated too!
The trick is to join the students and visits into a collection that contains data of both:
from ei in eventInstances
from sm in ei.StaffMembers
from x in
(from vi in ei.Visits
join st in ei.Students on vi.PersonId equals st.Id
select new { vi, st }) // Here you get students and visits side-by-side
select new
{
ei.EventId,
Event = ei.Name,
StaffMemeber = sm.Name,
PersonId = x.st.Id,
Student = x.st.Name
}
Related
I have two JSONs files Country & Ceremony
Country JSON:
[
{
"Short": "AF",
"Name": "Afghanistan"
},
{
"Short": "AN",
"Name": "Netherlands Antilles"
},
{
"Short": "AI",
"Name": "Anguilla"
},
{
"Short": "AL",
"Name": "Albania"
} ]
Ceremony JSON:
[
{
"CName": "Fitr",
"CStart": "2021-11-10T09:00:00",
"CEnd": "2021-11-14T09:00:00",
"Loc": {
"Info": "",
"Short": "AF"
}
},
{
"CName": "Azha",
"CStart": "2023-06-17T09:18:44",
"CEnd": "2023-06-18T09:18:44",
"Loc": {
"Info": "",
"Short": "AI"
}
},
{
"CName": "Azha",
"CStart": "2022-01-05T00:00:00",
"CEnd": "2022-01-05T23:59:59",
"Loc": {
"Info": "",
"Short": "AL"
}
},
{
"CName": "Fitr",
"CStart": "2022-01-05T00:00:00",
"CEnd": "2022-01-05T23:59:59",
"Loc": {
"Info": "",
"Short": "AN",
}
}
]
Country Model Class
public class Country
{
public string Short{ get; set; }
public string Name { get; set; }
}
Ceremony Model Class
public class Ceremony
{
public string CName { get; set; }
public DateTime CStart { get; set; }
public DateTime End { get; set; }
public Loc loc { get; set; }
}
Loc Model Class
public class Loc
{
public string Info { get; set; }
public string Short { get; set; }
}
I want to show Country (Name) with a connection to Ceremony, Loc, and Short, so that when I read the Ceremony data in front of Short, I can see the full name of the country. Country full name should come from Country JSON.
Results should be like this:
CName CStart CEnd Short Name
Fitr "" "" AF Afghanistan
Azha "" "" AI Anguilla
How can I use LINQ to display the top countries i.e., using (Short) with the most ceremonies in 2021?
You can join two entities on ShortName like below :
var countries = ...;
var ceremonies = ...;
var result = (from c in countries
join ce in ceremonies on c.Short equals ce.loc.Short
select new {
ce.CName,
ce.CStart,
ce.Cend,
c.Short,
c.Name
}).Where(r=> r.CStart.Year == 2021).
GroupBy(r=> r.Short).Select(r=> new { Short = r.Key,
EventCount = r.Count()}).OrderByDescending(r=> r.EventCount)
.ToArray();
Edit
Added grouping and sorting as the question evolves.
I have list of User and Department Like below:
public class Users
{
public int id { get; set; }
public string jobTitle { get; set; }
public int officeLocation { get; set; }
public string userPrincipalName { get; set; }
}
public class Departments
{
public int id { get; set; }
public string department { get; set; }
public string displayName { get; set; }
}
Here is my Json
"Departments": [
{
"department": "Azure",
"id": "1",
"displayName": "Thad"
},
{
"department": "Visual Studio",
"id": "2",
"displayName": "Scott Hansalman"
},
{
"department": "C#",
"id": "3",
"displayName": "Paul"
}
]
"Users": [
{
"jobTitle": "Senior Program manager ",
"officeLocation": "Redmond",
"userPrincipalName": "thad.teams.com",
"id": "1"
},
{
"jobTitle": ""Technical Lead,
"officeLocation": "Redmond",
"userPrincipalName": "scott.teams.com",
"id": "2"
},
{
"jobTitle": "Development Engineer II",
"officeLocation": "Canada",
"userPrincipalName": "paul.teams.com",
"id": "3"
}
]
I want to join two list using linq where I would pass id of user
and get department.
I tried like this
var query = from user in Users
join dept in Departments
on user.id equals dept.id
select new
{
user.id ,
user.jobTitle,
user.officeLocation,
dept.department
}.where(id = 1) ;
But where clause doesn't seems okay, say's where doesn't exits in current context
This will work, you're just missing some ( )s, and there is a syntax error in the where...
(from user in Users
join dept in Departments
on user.id equals dept.id
select new
{
user.id ,
user.jobTitle,
user.officeLocation,
dept.department
}).Where(c => c.id == 1) ;
But usually, the Where is done upfront, as query expression.
How could I find a specific id in this list?
var contactList = JsonConvert.DeserializeObject<ContactList>(jsonString);
contactList.contacts.FindAll(x => x.id == item.id);
The code above is not filtering by id and is returning all rows from object.
(Visual Studio is not showing me .Where clause only .Find and .FindAll)
C# code
namespace RestDemo.Model
{
public class Phone
{
public string mobile { get; set; }
public string home { get; set; }
public string office { get; set; }
}
public class Contact
{
public int id { get; set; }
public string name { get; set; }
public string email { get; set; }
public string address { get; set; }
public string gender { get; set; }
public Phone phone { get; set; }
}
public class ContactList
{
public List<Contact> contacts { get; set; }
}
}
Json:
{ "contacts": [ { "id": 200, "name": "Ravi Tamada", "email": "ravi#gmail.com", "address": "xx-xx-xxxx,x - street, x - country", "gender": "male", "phone": { "mobile": "+91 0000000000", "home": "00 000000", "office": "00 000000" } }, { "id": 201, "name": "Klev Krist", "email": "klev#gmail.com", "address": "xx-xx-xxxx,x - street, x - country", "gender": "male", "phone": { "mobile": "+91 0000000000", "home": "00 000000", "office": "00 000000" } }, { "id": 202, "name": "Paul Neil", "email": "paul.neil#gmail.com", "address": "xx-xx-xxxx,x - street, x - country", "gender": "male", "phone": { "mobile": "+91 0000000000", "home": "00 000000", "office": "00 000000" } } ]}
Thanks
The FindAll method does not assign an object to the search result.
You have to keep the search result somewhere.
Example Multi Result
If you are expecting multiple results
var contactList = JsonConvert.DeserializeObject<ContactList>(jsonString);
var findedContact = contactList.contacts.FindAll(x => x.id == item.id);
//You business codes..
Example Single Result
If you are only waiting for 1 result
var contactList = JsonConvert.DeserializeObject<ContactList>(jsonString);
var oneContact = contactList.contacts.Find(x => x.id == item.id);
if(oneContact ==null){
//not found business codes
}
else {
//find result business codes
}
Assuming you want to find a certain id, we'll call it
var idToFind = "myID";
To find all contacts with said ID:
var contacts = contactList.contacts.Where(contact=> contact.id == idToFind);
To find at least one contact with said ID:
var contactWithID = contactList.contacts.FirstOrDefault(contact=> contact.id == idToFind);
// Before using, check if null, means no contact matched the id.
if(contactWithID != null)
{
// A contact was found.
}
else
{
// No contact matching that id is found.
}
Specific to your case, I am using the same Model structure to deserialize your JSON and then use the Where linq clause to achieve what you require. A working fiddle can be found at: https://dotnetfiddle.net/SAcFja
Code:
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var jsonString = #"{ 'contacts': [{ 'id': 200, 'name': 'Ravi Tamada', 'email': 'ravi#gmail.com', 'address': 'xx-xx-xxxx,x - street, x - country', 'gender': 'male', 'phone': { 'mobile': '+91 0000000000', 'home': '00 000000', 'office': '00 000000' } }] }";
var data= JsonConvert.DeserializeObject<ContactList>(jsonString);
//Console.WriteLine(data.contacts);
var found=data.contacts.Where(x=>x.id.ToString()=="200");
foreach(var value in found)
{
Console.WriteLine(value.id);
Console.WriteLine(value.address);
}
}
}
public class Phone
{
public string mobile { get; set; }
public string home { get; set; }
public string office { get; set; }
}
public class Contact
{
public string id { get; set; }
public string name { get; set; }
public string email { get; set; }
public string address { get; set; }
public string gender { get; set; }
public Phone phone { get; set; }
}
public class ContactList
{
public List<Contact> contacts { get; set; }
}
Output when id=200:
200
xx-xx-xxxx,x - street, x - country
As per your comment on #Tenretni's answer, I guess you missed to use System.Linq library in your code.
Import System.Collections.Generic and System.Linq in your code and use FirstOrDefault() or .Where() clause
using System.Collections.Generic;
using System.Linq;
//…
string jsonString = #"{ 'contacts': [{ 'id': 'c200', 'name': 'Ravi Tamada', 'email': 'ravi#gmail.com', 'address': 'xx-xx-xxxx,x - street, x - country', 'gender': 'male', 'phone': { 'mobile': '+91 0000000000', 'home': '00 000000', 'office': '00 000000' } }] }";
var contactList = JsonConvert.DeserializeObject<ContactList>(jsonString);
var item = "c200";
var result = contactList.contacts.FirstOrDefault(x => x.id == item);
Console.WriteLine(result.name);
//If you have multiple records with same ID then you can try where clause
var result = contactList.contacts.Where(x => x.id == item); //Here result will be list of Contact
.Net Fiddle
I am getting familiar with C# and Linq and appreciate any help. It should be easy for someone who works with it. I have a Json object that returns contact information. I also have a list of ids. I need to compare the list to the Json object and wherever the value in the list matches the userclientcode in the Json object, I need to extract the following information (only for the matches):
clienttaxonomy (if not empty)
fullname (if not empty)
[0]contactdata ( -> email if not null or empty)
[1]contactdata (-> address if not null or empty)
[2]contactdata (-> phone number if not null or empty)
First List
var fileContactIds = new List<string> { "5678765", "2135123", "12341234", "341234123", "12341234123", "2341234123", "341234123", "123412341", "13342354",
"12342341", "123412322", "163341234", "2345234115", "8967896", "75626234 };
JSON object returned with:
return JsonConvert.DeserializeObject<RelatedContacts>(json)?.list;
This is the Json object:
[![Json object][1]][1]
This is the Json string (unescaped):
{
"type": "com.kurtosys.api.userprofile.domain.RelatedContactList",
"list": [{
"objectlistid": 5678765,
"objectlisttypeid": 4567876,
"objectlistname": "ALL.National",
"clienttaxonomyid": 765677,
"clienttaxonomy": "National Wholesaler",
"order": 1,
"contacts": [{
"personid": 7654345678,
"fullname": "Person Jallo",
"userid": 876567,
"userclientcode": "341234123",
"contactdetails": [{
"contactid": 8765567,
"contacttypeid": 4565,
"contactdata": "person.contact#site.com"
}, {
"contactid": 876545678,
"contacttypeid": 4565,
"contactdata": "Baltimore,MD,21209,United States"
}, {
"contactid": 87654567,
"contacttypeid": 4584,
"contactdata": "410-413-2640"
}]
}]
}, {
"objectlistid": 765678,
"objectlisttypeid": 40400461,
"objectlistname": "RM.Internal",
"clienttaxonomyid": 7567898,
"clienttaxonomy": "Internal Regional Wholesaler",
"order": 2,
"contacts": [{
"personid": 56789876,
"fullname": "Jackson Man",
"userid": 876567,
"userclientcode": "1012275",
"contactdetails": [{
"contactid": 309598309,
"contacttypeid": 76546,
"contactdata": "mister.jackson##site.com.com"
}, {
"contactid": 876567,
"contacttypeid": 4581,
"contactdata": "Baltimore,MD,21209,United States"
}, {
"contactid": 876567,
"contacttypeid": 2342,
"contactdata": "123-413-2604"
}]
}]
}, {
"objectlistid": 309571364,
"objectlisttypeid": 40400461,
"objectlistname": "RM.External",
"clienttaxonomyid": 309580710,
"clienttaxonomy": "External Regional Wholesaler",
"order": 3,
"contacts": [{
"personid": 302736188,
"fullname": "Phal Sumi",
"userid": 303826019,
"userclientcode": "163341234",
"contactdetails": [{
"contactid": 309598253,
"contacttypeid": 2342,
"contactdata": "misters.emailas#site.com"
}, {
"contactid": 309611930,
"contacttypeid": 2342,
"contactdata": "Baltimore,MD,21209,United States"
}, {
"contactid": 34234132,
"contacttypeid": 3422,
"contactdata": "342-803-1793"
}]
}]
}]
}
How do I
1] Select using Linq and Lambdas and put in a list fullname, email, address etc from the deserialized object ?
2]compare with first list and only transfer those items where the userclientcode == the number in list A.
I have tried:
var query5 = relatedContact.Where(s => s.objectlistid == Convert.ToInt64(contacts.Select(t => t.id)))
var selected = relatedContact.Where(p => p.contacts
.Any(a => fileContactIds.Contains(p.contacts))
.ToList();
var query2 = relatedContact.Where(s => s.objectlistid == Convert.ToInt64(contacts.Select(t => t.id)))
.Select(s => new
{
Description = s.clienttaxonomy,
Fullname = s.contacts[0].fullname,
Email = s.contacts[0].contactdetails[0].contactdata,
Address = s.contacts[0].contactdetails[1].contactdata,
PhoneNumber = s.contacts[0].contactdetails[2].contactdata
});
But don't really know what I'm doing it seems. Any suggestions on how to get the required sections ? I think part of the reason is that the contactdata is a list.
Thanks all
You can create a classes for the desearlization of JSON Object like this
public class Rootobject
{
public string type { get; set; }
public List[] list { get; set; }
}
public class List
{
public int objectlistid { get; set; }
public int objectlisttypeid { get; set; }
public string objectlistname { get; set; }
public int clienttaxonomyid { get; set; }
public string clienttaxonomy { get; set; }
public int order { get; set; }
public Contact[] contacts { get; set; }
}
public class Contact
{
public long personid { get; set; }
public string fullname { get; set; }
public int userid { get; set; }
public string userclientcode { get; set; }
public Contactdetail[] contactdetails { get; set; }
}
public class Contactdetail
{
public int contactid { get; set; }
public int contacttypeid { get; set; }
public string contactdata { get; set; }
}
And then to extract the selected information we can also create a another class like
public class ExtractedInfo
{
public string ocClientTaxonomy { get; set; }
public string ocFullName { get; set; }
public CTDetails ocContactDetails { get; set; }
}
public class CTDetails
{
public string ocCTAddress { get; set; }
public string ocCTEmail { get; set; }
public string ocCTPhoneNumber { get; set; }
}
Now we have to find all the data from JSON
var fileContactIds = new List<string> { "5678765", "2135123", "12341234", "341234123", "12341234123", "2341234123", "341234123", "123412341", "13342354", "12342341", "123412322", "163341234", "2345234115", "8967896", "75626234" };
//Read JSON from txt file. You can do it by your way
string myjson = File.ReadAllText("Some.txt");
string ctphno, ctadd, ctemail, cltax, ctfullname;
List<ExtractedInfo> ei = new List<ExtractedInfo>();
CTDetails ctdtl = new CTDetails();
ExtractedInfo eiex = new ExtractedInfo();
//Deserialize the JSON string to Object.
Rootobject AllData = JsonConvert.DeserializeObject<Rootobject>(myjson);
//Finding all data in List Class
foreach(List lst in AllData.list)
{
cltax = lst.clienttaxonomy; // you can directly put eiex.ocClientTaxonomy = lst.clienttaxonomy;
foreach(Contact ct in lst.contacts)
{
//To check if value in the list matches the objectlistid in the Json object
if(fileContactIds.Contains(lst.objectlistid.ToString()))
{
ctfullname = ct.fullname; // you can directly put eiex.ocFullName = ct.fullname;
foreach(Contactdetail ctd in ct.contactdetails)
{
//Here we are trying to find the Match for Email.
if(Regex.IsMatch(ctd.contactdata, #"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z", RegexOptions.IgnoreCase))
{
ctemail = ctd.contactdata;
ctdtl.ocCTEmail = ctemail;
}
//Here We trying to find the match for Phone Number.
else if(Regex.IsMatch(ctd.contactdata, #"\(?\d{3}\)?-? *\d{3}-? *-?\d{4}", RegexOptions.IgnoreCase))
{
ctphno = ctd.contactdata;
ctdtl.ocCTPhoneNumber = ctphno;
}
//If NOthing matches than it might be address (Assumed)
else
{
ctadd = ctd.contactdata;
ctdtl.ocCTAddress = ctadd;
}
}
eiex.ocFullName = ctfullname;
}
}
eiex.ocClientTaxonomy = cltax;
eiex.ocContactDetails = ctdtl;
ei.Add(eiex);
}
Hope this helps and fit in your requirements.
I want to deserialize JSON data (using Newtonsoft) similar to following, and convert to a strongly-typed object/list in C#, but can't figure out how to define the class such that indexed references are converted to the referenced objects.
{
"Countries": [
{
"Name": "USA",
},
{
"Name": "UK",
},
{
"Name": "JAPAN",
},
],
"Authors": [
{
"DisplayName": "John Doe",
"RealName": "Not John Doe"
},
{
"DisplayName": "Jane Doe",
"RealName": "Not Jane Doe"
},
],
"Books": [
{
"Author": 0,
"Title": "A good read",
"PublishedCountries": "0,1",
},
{
"Author": 0,
"Title": "Another good read",
"PublishedCountries": "0,1",
},
{
"Author": 1,
"Title": "This one is even better",
"PublishedCountries": "0,1,2",
},
],
}
Ideally, I'd like to use classes similar to following:
public class Country
{
public string Name { get; set;}
}
public class AuthorDetails
{
public string DisplayName { get; set; }
public string RealName { get; set; }
}
public class Book
{
public AuthorDetails Author { get; set; }
public string Title { get; set; }
public IEnumerable<Country> PublishedCountries { get; set; }
}
public class ListOfBooks
{
public IEnumerable<Book> Books { get; set; }
}
And deserialize like this:
var listOfBooks = JsonConvert.DeserializeObject<ListOfBooks>(jsonAsString);
I'm stuck as how to tell Json.Net that the Author property in the book JObject is an index, rather than an integer. Same goes for the PublishedCountries (that's comma-separated list of indexes)
I can't see a way other than helping the deserialization process a little bit.
var dynObj = (JObject)JsonConvert.DeserializeObject(json);
var authors = dynObj["Authors"]
.Select(j => new AuthorDetails {
RealName = (string)j["RealName"],
DisplayName = (string)j["DisplayName"]
})
.ToList();
var countries = dynObj["Countries"]
.Select(j => new Country { Name = (string)j["Name"]})
.ToList();
var books = dynObj["Books"].Select(x => new Book
{
Author = authors[(int)x["Author"]],
Title = (string)x["Title"],
PublishedCountries = x["PublishedCountries"].ToString().Split(',')
.Select(i =>countries[int.Parse(i)])
.ToList()
})
.ToList();
public class Country
{
public string Name { get; set; }
}
public class AuthorDetails
{
public string DisplayName { get; set; }
public string RealName { get; set; }
}
public class Book
{
public AuthorDetails Author { get; set; }
public string Title { get; set; }
public List<Country> PublishedCountries { get; set; }
}
I believe what you want to do is 'preserve object references'.
You can mark-up your C# object with attributes to describe when to utilise a reference, rather than duplicate the content of the object all over again:
[JsonObject(IsReference = true)] (use on the type declaration)
However, your generated Javascript will not look quite like what you have demonstrated, take a look here to see how to do it.
http://james.newtonking.com/projects/json/help/?topic=html/PreserveObjectReferences.htm
Instead, your JSON will look more like this:
{
"Countries": [
{
"Name": "USA",
},
{
"Name": "UK",
},
{
"Name": "JAPAN",
},
],
"Authors": [
{
"DisplayName": "John Doe",
"RealName": "Not John Doe"
},
{
"DisplayName": "Jane Doe",
"RealName": "Not Jane Doe"
},
],
"Books": [
{
"$id": 1,
"Author": 0,
"Title": "A good read",
"PublishedCountries": "0,1",
},
{
"$ref": 1
},
{
"Author": 1,
"Title": "This one is even better",
"PublishedCountries": "0,1,2",
},
],
}