C# Json deserisalization - c#

In C# how can I select only "GroupType" from the json below.
Thanks.
{
"QnACollection": {
"QnA": [
{
"id": 11,
"question": "What was your childhood nickname?"
},
{
"id": 12,
"question": "In what city was your mother born?"
},
{
"GroupType": "RUN",
"id": 45,
"question": "What is the first name?"
}
]
}
}

Using Json.Net
var value = (string)JObject.Parse(json)
.Descendants().OfType<JProperty>()
.FirstOrDefault(p => p.Name == "GroupType");

Related

Array name is random every time C# complex Json

This is the Json I am working with:
{
"field_1": 918237,
"field_2": "test",
"field_3": 918237,
"field_4": [
{
"Type": "test",
"field_5": {
"id": "aasd812736",
"time": "2018-03-29T20:34:33.910Z",
"last_time": "2022-11-16T17:30:54.579Z",
"ext": 123,
"exp": 5,
"id_full": "aasd8127367618253172",
"moreId": 87162387,
"version": "v1.5",
"items": {
"RANDOM ID_1": {
"template": "ineedthis_1",
"attributes": {
"lvl_at": 1,
"has_at": true,
"variants": {
"channel": "progressive",
"active": "lvl1",
"owned": [
" lvl 1 ",
" lvl 2 ",
" lvl 3 ",
" lvl 4 ",
" lvl 5 "
]
}
}
},
"RANDOM ID_2": {
"template": "ineedthis_2",
"attributes": {
"lvl_at": 1,
"has_at": true,
"variants": {
"channel": "progressive",
"active": "lvl1"
}
}
},
"RANDOM ID_3": {
"template": "ineedthis_3",
"attributes": {
"lvl_at": 1,
"has_at": true,
"variants": {
"channel": "progressive",
"active": "lvl1",
"owned": [
" lvl 2 ",
" lvl 3 ",
" lvl 4 ",
" lvl 5 "
]
}
}
},
"RANDOM ID_4": {
"template": "ineedthis_4",
"attributes": {
"lvl_at": 1,
"has_at": true,
"variants": {
"channel": "progressive",
"active": "lvl1"
}
}
},
"RANDOM ID_5": {
"template": "ineedthis_5",
"attributes": {
"lvl_at": 1,
"has_at": true,
"variants": {
"channel": "progressive",
"active": "lvl1"
}
}
},
"RANDOM ID_6": {
"template": "ineedthis_6",
"attributes": {
"lvl_at": 1,
"has_at": true,
"variants": {
"channel": "progressive",
"active": "lvl1"
}
}
},
"RANDOM ID_7": {
"template": "ineedthis_7",
"attributes": {
"lvl_at": 1,
"has_at": true,
"variants": {
"channel": "progressive",
"active": "lvl1",
"owned": [
" lvl 2 ",
" lvl 3 "
]
}
}
}
}
},
"stats": [
{
"attributes": {
"lifetime": 100,
"book": false,
"past_experience": [
{
"seas_id": 3,
"seas_wi": 100,
"seas_lv": 40,
"book_lv": 30
},
{
"seas_id": 4,
"seas_wi": 310,
"seas_lv": 5,
"book_lv": 30
},
{
"seas_id": 5,
"seas_wi": 150,
"seas_lv": 51,
"book_lv": 32
}
]
}
}
]
}
]
}
So basically, the RANDOM ID_1 to 7 are randomly generated everytime by the API, I want to get the value from the template to a string for each one of the IDs and if there is a variant I want to get the maximum variant that is available, when available(Ex. ID_7 has max lvl 3 but ID_3 has max lvl 5).
It would be so much easier if the array name was not random for these. I've been searching the whole day on stackoverflow and other websites but can't seem to find anyone with a similar issue to this.
If you have answered this question before, please send me the link. Would appreciate it a lot!
I've tried
var user = JsonConvert.DeserializeObject<dynamic>(json);
Console.WriteLine(user.template);
But this way it returns me the null exception for the user . Also thinking that I cannot check the variants this way.
Instead of dynamic , I prefer to use Parse
var items = ((JObject)JObject.Parse(json)["field_4"][0]["field_5"]["items"]);
List<Result> result = items.Properties().Select(x => new Result
{
Id = x.Name,
Template = (string)x.Value["template"],
MaxLevel = x.Value["attributes"]["variants"]["owned"] == null ?
"N/A" : x.Value["attributes"]["variants"]["owned"][x.Value["attributes"]["variants"]["owned"].Count() - 1].ToString().Trim()
}).ToList();
public class Result
{
public string Id { get; set; }
public string Template { get; set; }
public string MaxLevel { get; set; }
}
or you can use an anonymous object instead of class
result
[
{
"Id": "RANDOM ID_1",
"Template": "ineedthis_1",
"MaxLevel": "lvl 5"
},
{
"Id": "RANDOM ID_2",
"Template": "ineedthis_2",
"MaxLevel": "N/A"
},
{
"Id": "RANDOM ID_3",
"Template": "ineedthis_3",
"MaxLevel": "lvl 5"
},
{
"Id": "RANDOM ID_4",
"Template": "ineedthis_4",
"MaxLevel": "N/A"
},
{
"Id": "RANDOM ID_5",
"Template": "ineedthis_5",
"MaxLevel": "N/A"
},
{
"Id": "RANDOM ID_6",
"Template": "ineedthis_6",
"MaxLevel": "N/A"
},
{
"Id": "RANDOM ID_7",
"Template": "ineedthis_7",
"MaxLevel": "lvl 3"
}
]

How to only return specific object list base on the condition

I want to add a condition to for returning selected object list. If the condition is met, it will not return the an item if its category is for this example, category is 3.
This is the query:
var objectQuery = query
.ToList()
.Select(a => new
{
a.Id,
ObjectDetails = (new ObjectClass[] { })
.Concat(...)
.Concat(...)
.Distinct()
.Select(f => new
{
f.ObjectDetails.Id,
f.ObjectDetails.Name,
f.ObjectDetails.DisplayName,
category = (int)f.ObjectDetails.Category,
f.ObjectDetails.IsArchived,
})
});
return objectQuery.ToList().FirstOrDefault();
i want to add a condition like this where if it met the condition, it will remove all items with category 3 and returns all the item if not, but i dont know how to properly implement it:
if(condition a)
return objectQuery.Select(...Where(category != 3)).ToList().FirstOrDefault();
else
return objectQuery.ToList().FirstOrDefault();
this is the return output:
{
"objectQuery": {
"id": 1198,
"ObjectDetails": [
{
"id": 1,
"name": "name one",
"displayName": "NAME 1",
"Category": 1,
},
{
"id": 2,
"name": "name two",
"displayName": "NAME 2",
"Category": 1,
},
{
"id": 3,
"name": "name three",
"displayName": "NAME 3",
"Category": 2,
},
{
"id": 4,
"name": "name four",
"displayName": "NAME 4",
"Category": 2,
},
{
"id": 5,
"name": "name five",
"displayName": "NAME 5",
"Category": 3,
},
{
"id": 6,
"name": "name six",
"displayName": "NAME 6",
"Category": 1,
},
{
"id": 7,
"name": "name seven",
"displayName": "NAME 7",
"Category": 1,
}
]
}
}
If I get your question properly then you'll need something like this:
var objectQuery = query
.ToList()
.Select(a => new
{
a.Id,
ObjectDetails = (new ObjectClass[] { })
.Concat(...)
.Concat(...)
.Distinct()
.Select(f => new
{
f.ObjectDetails.Id,
f.ObjectDetails.Name,
f.ObjectDetails.DisplayName,
category = (int)f.ObjectDetails.Category,
f.ObjectDetails.IsArchived,
})
.Where(f => !condition || f.category != 3)
});
return objectQuery.ToList().FirstOrDefault();

Retrieving list of documents from collection by id in nested list

I have documents like this:
[
// 1
{
"_id": ObjectId("573f3944a75c951d4d6aa65e"),
"Source": "IGN",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "Japan",
}
]
}
]
},
// 2
{
"_id": ObjectId("573f3d41a75c951d4d6aa65f"),
"Source": "VG",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "USA"
}
]
}
]
},
// 3
{
"_id": ObjectId("573f4367a75c951d4d6aa660"),
"Source": "NRK",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "Germany"
}
]
}
]
},
// 4
{
"_id": ObjectId("573f4571a75c951d4d6aa661"),
"Source": "VG",
"Family": [
{
"Countries": [
{
"uid": 10,
"name": "France"
}
]
}
]
},
// 5
{
"_id": ObjectId("573f468da75c951d4d6aa662"),
"Source": "IGN",
"Family": [
{
"Countries": [
{
"uid": 14,
"name": "England"
}
]
}
]
}
]
I want to return only the documents with source equals 'Countries.uid' equal 17
so I have in the end :
[
{
"_id": ObjectId("573f3944a75c951d4d6aa65e"),
"Source": "IGN",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "Japan",
}
]
}
]
},
{
"_id": ObjectId("573f3d41a75c951d4d6aa65f"),
"Source": "VG",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "USA"
}
]
}
]
},
{
"_id": ObjectId("573f4367a75c951d4d6aa660"),
"Source": "NRK",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "Germany"
}
]
}
]
}
]
How can I do this with the official C# MongoDB driver?
Tried this :
public List<Example> getLinkedCountry(string porduitId)
{
var filter = Builders<Example>.Filter.AnyIn("Family.Countries.uid", porduitId);
var cursor = await _certificats.FindAsync(filter);
var docs = cursor.ToList();
return docs;
}
Unfortunately, I think my filter is wrong.
Is there a way to find all the documents by accessing the nested list by id and retrieving it?
Solution 1
Use ElemMatch instead of AnyIn.
var filter = Builders<Example>.Filter.ElemMatch(
x => x.Family,
y => y.Countries.Any(z => z.uid == porduitId));
Output
Solution 2
If you are unconfident with MongoDB .Net Driver syntax, you can convert the query as BsonDocument via MongoDB Compass (Export to language feature).
var filter = new BsonDocument("Family.Countries.uid", porduitId);
Just to expand on #Yong Shun 's answer,
if you just want to return the list of nested documents and not all of it, you have a few options.
Using project
var filter = Builders<Example>.Filter.ElemMatch(
x => x.Family,
y => y.Countries.Any(z => z.uid == porduitId));
var project = Builders<Example>.Project.ElemMatch(
x => x.Family,
y => y.Countries.Any(z => z.uid == porduitId)
);
var examples = await collection.filter(filter).Project<Example>(project).toListAsync();
Using the aggregate pipeline
var filter = Builders<Example>.Filter.ElemMatch(
x => x.Family,
y => y.Countries.Any(z => z.uid == porduitId));
var project = Builders<ServiceProvider>.Projection.Expression(
x => x.Faimily.Where(y => y.uid == porduitId)
);
var result = await collection
.Aggregate()
.Match(filter)
.Project(project)
.ToListAsync(); //Here result is a list of Iterable<Countries>

Zip collections matching by ID

This is a repost of a previous question that was wrongly closed as a duplicate:
Say I have two collections of the same type similar to the following:
OldCollection: [{ID: 1, other props}, {ID: 2, other props}, {ID: 3, other props}]
NewCollection: [{ID: 1, other props}, {ID: 3, other props}, {ID: 4, other props}]
Is there a way to zip the collections matching ID's to get a Tuple result like the following:
[{OLD-ID1, NEW-ID1},
{OLD-ID2, null},
{OLD-ID3, NEW-ID3},
{null, NEW-ID4}]
So basically I want to zip the collections together matching on ID and if only one collection has an entry with a particular ID the Tuple should fill in null for that spot.
IMPORTANT: This is not a duplicate of the full outer join solution. I do not want to combine my results so that Col1-ID1 gets merged with Col2-ID1. I Just want to Tuple them so I can see them side by side. Think of it as Collection 1 is the old values and Collection 2 is the new values. I want them to be paired up into Tuples so I can see ID1 and ID3 were updated, ID2 was removed, and ID4 was added.
Here is a DotNetFiddle example that almost does what I want.
The results of that fiddle is:
[
{
"Item1": {
"id": 1,
"name": "firstOld"
},
"Item2": {
"id": 1,
"name": "firstNew"
}
},
{
"Item1": {
"id": 2,
"name": "secondOld"
},
"Item2": {
"id": 3,
"name": "thirdNew"
}
},
{
"Item1": {
"id": 3,
"name": "thirdOld"
},
"Item2": {
"id": 4,
"name": "fourthNew"
}
},
{
"Item1": null,
"Item2": {
"id": 5,
"name": "fifthNew"
}
}
]
What I want is this:
[
{
"Item1": {
"id": 1,
"name": "firstOld"
},
"Item2": {
"id": 1,
"name": "firstNew"
}
},
{
"Item1": {
"id": 2,
"name": "secondOld"
},
"Item2": null
},
{
"Item1": {
"id": 3,
"name": "thirdOld"
},
"Item2": {
"id": 3,
"name": "thirdNew"
}
},
{
"Item1": null,
"Item2": {
"id": 4,
"name": "fourthNew"
}
},
{
"Item1": null,
"Item2": {
"id": 5,
"name": "fifthNew"
}
}
]
You want a full-outer-join anyway, but you could use this easy approach:
var oldByID = oldCollection.ToDictionary(x => x.Id);
var newByID = newCollection.ToDictionary(x => x.Id);
IEnumerable<int> allIds = oldByID.Keys.Union(newByID.Keys);
var oldAndNew = allIds.Select(id =>
(Old: oldByID.TryGetValue(id, out var oldObj) ? oldObj : null,
New: newByID.TryGetValue(id, out var newObj) ? newObj : null));
So first create two dictionaries to lookup the old and new objects via Id efficiently. Then collect all Id's and use Select to get the old/new object with each Id. If it's not available in the dictionary it will assign null to the tuple item.

Parsing LuisResult to get values field

I have a LuisResult variable called result that has JSON info like
{
"query": "what is twenty * three",
"topScoringIntent": {
"intent": "Multiplication",
"score": 0.740870655
},
"intents": [
{
"intent": "Multiplication",
"score": 0.740870655
},
{
"intent": "Subtraction",
"score": 0.04339512
},
{
"intent": "None",
"score": 0.0164503977
},
{
"intent": "addition",
"score": 0.0126439808
},
{
"intent": "Division",
"score": 0.0108866822
}
],
"entities": [
{
"entity": "twenty",
"type": "builtin.number",
"startIndex": 8,
"endIndex": 13,
"resolution": {
"value": "20"
}
},
{
"entity": "three",
"type": "builtin.number",
"startIndex": 17,
"endIndex": 21,
"resolution": {
"value": "3"
}
}
]
}
I'm trying to access the "value" field under "resolution" since it converts string representations of numbers to digit representation. At the moment I'm just trying to get the first value. I've tried to extract the value this way
var valuesEntity = result.Entities; //IList of all entities
string s = "";
s = valuesEntity[i].Resolution.Values.ToString(); //extract value field??
await context.PostAsync($"{s}"); //post to emulator
This prints out System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.String]
to me. What am I missing to be able to get the "values" field?
Try
valuesEntity[i].Resolution.Values[0].ToString();
Values is a collection of strings.
You can also use linq and do:
valuesEntity[i].Resolution.Values.FirstOrDefault();

Categories