c# Json get all parent and child values - c#

I have a json string.
There are multiple subcategories within the json string depending on the category.
I want to combine them all.
It should always give the Id of the last child level of a higher level.
Sample :
Id - Name
-- ----------
1239 - Accessory> Jewelery > wristband> Silver wristband
Can anyone help me . Thanks
{
"categories": [
{
"id": 368,
**"name": "Accessory ",**
"parentId": null,
"subCategories": [
{
"id": 396,
**"name": "Jewelery ",**
"parentId": 368,
"subCategories": [
{
"id": 397,
**"name": "wristband",**
"parentId": 396,
"subCategories": [
{
"id": 1238,
"name": "Gold wristband",
"parentId": 397,
"subCategories": []
},
{
**"id": 1239,**
"name": "Silver wristband",
"parentId": 397,
"subCategories": []
},
{
"id": 2845,
"name": "Steel wristband",
"parentId": 397,
"subCategories": []
},
{
"id": 3171,
"name": "Pearl wristband",
"parentId": 397,
"subCategories": []
},
{
"id": 3883,
"name": "diamond wristband",
"parentId": 397,
"subCategories": []
}
]
}
]
}
]
}
]
}
Here my class
public class SubCategory
{
public int id { get; set; }
public string name { get; set; }
public int parentId { get; set; }
public List<object> subCategories { get; set; }
}
public class Category
{
public int id { get; set; }
public string name { get; set; }
public object parentId { get; set; }
public List<SubCategory> subCategories { get; set; }
}
public class Root
{
public List<Category> categories { get; set; }
}

I think you can drop SubCategory, what is that List<object> doing there anyway?
Assuming you can deserialize
public class Category
{
public int id { get; set; }
public string name { get; set; }
public int? parentId { get; set; } // int?
public List<Category> subCategories { get; set; } // <Category>
}
public class Root
{
public List<Category> categories { get; set; }
}
then you can use a simple depth-first recursive visitor:
string FindCategoryTrail(List<Category> categories, int id)
{
foreach(var category in categories)
{
if (category.id == id) return category.name;
var trail = FindCategoryTrail(category.subCategories , id);
if (trail != null)
{
return category.name + " > " + trail;
}
}
return null;
}
and call it like
string trail = FindCategoryTrail(myRoot.categories, 1239);

using Linq, you could flatten the nested lists:
public class Category
{
public int id { get; set; }
public string name { get; set; }
public object parentId { get; set; }
public List<Category> subCategories { get; set; }
}
public class Root
{
public List<Category> categories { get; set; }
}
IEnumerable<Category> Flatten(IEnumerable<Category> e) => e.SelectMany(c => Flatten(c.subCategories)).Concat(e);
Root root = JsonConvert.DeserializeObject<Root>(File.ReadAllText(#"U:\test1.json"));
var search = Flatten(root.categories).Where(c => c.id == 1239);
foreach(var s in search)
{
System.Diagnostics.Debug.WriteLine($"id: {s.id}");
System.Diagnostics.Debug.WriteLine($"name: {s.name}");
System.Diagnostics.Debug.WriteLine($"parentid: {s.parentId}");
}

Related

Is possible return data from two tables in ICollection using LINQ?

This is my first question, I hope to do it correctly.
I am starting to use an ASP.NET Core Web API and I have a question.
I have the following models:
public class Pokemon
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime BirthDate { get; set; }
public ICollection<Review> Reviews { get; set; }
public ICollection<PokemonOwner> PokemonOwners { get; set; }
public ICollection<PokemonCategory> PokemonCategories { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<PokemonCategory> PokemonCategories { get; set; }
}
public class PokemonCategory
{
public int PokemonId { get; set; }
public int CategoryId { get; set; }
public Pokemon Pokemon { get; set; }
public Category Category { get; set; }
}
I'm trying to display in an endpoint of my controller where it shows me together the pokemons and their corresponding category.
I have tried to make a join between the two tables but it is impossible to get the expected result (return the pokemons and its category).
public List<Category> GetPokemonAndCategory(int pokemonid, int categoryid)
{
return _context.Categories
.Include(a => a.PokemonCategories)
.Where(c => c.Id == categoryid).ToList();
}
With this code, I get this data returned:
[
{
"id": 2,
"name": "Water",
"pokemonCategories": [
{
"pokemonId": 2,
"categoryId": 2,
"pokemon": null,
"category": null
}
]
}
]
Can you help me? Thanks!
Return pokemons and categories in the same query
EDIT
This works with cemahseri answer, if i change the DTO for something like this;
public class PokemonCategoryDto
{
public Pokemon Pokemon { get; set; }
// public Category Category { get; set; }
}
but i get this result;
{
"pokemon": {
"id": 2,
"name": "Squirtle",
"birthDate": "1903-01-01T00:00:00",
"reviews": null,
"pokemonOwners": null,
"pokemonCategories": [
{
"pokemonId": 2,
"categoryId": 2,
"pokemon": null,
"category": {
"id": 2,
"name": "Water",
"pokemonCategories": [
null
]
}
}
]
}
}
i think is because mi pokemon class have the other classes, how i can not show it like this?
{
"pokemon": {
"id": 2,
"name": "Squirtle",
"birthDate": "1903-01-01T00:00:00",
"pokemonCategories": [
{
"pokemonId": 2,
"categoryId": 2,
"category": {
"id": 2,
"name": "Water",
}
}
]
}
}
You can create DTO and return any data you want from that action. It's also recommended to use DTOs. Because sometimes you might not want to expose all properties in those classes. For example, let's say you have a DTO like this;
public class PokemonDto
{
public Pokemon Pokemon { get; set; }
public Category Category { get; set; }
}
Then you can get Pokémon and its category then return it from the action like this;
public async Task<IActionResult> GetPokemons(int pokemonId, int categoryId)
{
var pokemon = await _databaseContext.Pokemons.FirstOrDefaultAsync(p => p.Id == pokemonId);
var category = await _databaseContext.Categories.FirstOrDefaultAsync(c => c.Id == categoryId);
return Ok(new PokemonDto
{
Pokemon = pokemon,
Category = category
});
}

How can i improve filter on JSON?

As a title, i'm trying to access some child by following solution from this thread C# JSON.Net parse and get list of all elements matching a value using LINQ .
Here is my code
var result = await response.Content.ReadAsStringAsync();
var jsonData = (JObject)JsonConvert.DeserializeObject(result);
var doc = (JContainer)jsonData["symbols"];
var results = doc.Descendants()
.OfType<JObject>()
.Where(x => x["filterType"] != null &&
x["filterType"].Value<string>() == "MARKET_LOT_SIZE").ToList();
Result is pretty good so far, Here is sample result what i get from trial and error
{
"stepSize": "0.001",
"filterType": "MARKET_LOT_SIZE",
"maxQty": "120",
"minQty": "0.001"
},
{
"stepSize": "0.001",
"filterType": "MARKET_LOT_SIZE",
"maxQty": "140",
"minQty": "0.002"
}
It turn out that result is skip a lot of child to check, but that's not what i expected
i still expect to check upper child to make sure i access child correctly.
Here is real response
{
"timezone": "UTC",
"serverTime": 1660492828507,
"futuresType": "U_MARGINED",
"rateLimits": [
{
"rateLimitType": "REQUEST_WEIGHT",
"interval": "MINUTE",
"intervalNum": 1,
"limit": 2400
},
{
"rateLimitType": "ORDERS",
"interval": "MINUTE",
"intervalNum": 1,
"limit": 1200
},
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 300
}
],
"exchangeFilters": [],
"assets": [
{
"asset": "USDT",
"marginAvailable": true,
"autoAssetExchange": "-10000"
},
{
"asset": "BTC",
"marginAvailable": true,
"autoAssetExchange": "-0.00100000"
},
{
"asset": "BNB",
"marginAvailable": true,
"autoAssetExchange": "-10"
},
{
"asset": "ETH",
"marginAvailable": true,
"autoAssetExchange": "-5"
},
{
"asset": "XRP",
"marginAvailable": true,
"autoAssetExchange": "0"
},
{
"asset": "ADA",
"marginAvailable": true,
"autoAssetExchange": "0"
},
{
"asset": "USDC",
"marginAvailable": true,
"autoAssetExchange": "-10000"
},
{
"asset": "DOT",
"marginAvailable": true,
"autoAssetExchange": "0"
},
{
"asset": "SOL",
"marginAvailable": true,
"autoAssetExchange": "0"
},
{
"asset": "BUSD",
"marginAvailable": true,
"autoAssetExchange": "-10000"
}
],
"symbols": [
{
"symbol": "BTCUSDT",
"pair": "BTCUSDT",
"contractType": "PERPETUAL",
"deliveryDate": 4133404800000,
"onboardDate": 1569398400000,
"status": "TRADING",
"maintMarginPercent": "2.5000",
"requiredMarginPercent": "5.0000",
"baseAsset": "BTC",
"quoteAsset": "USDT",
"marginAsset": "USDT",
"pricePrecision": 2,
"quantityPrecision": 3,
"baseAssetPrecision": 8,
"quotePrecision": 8,
"underlyingType": "COIN",
"underlyingSubType": [
"PoW"
],
"settlePlan": 0,
"triggerProtect": "0.0500",
"liquidationFee": "0.015000",
"marketTakeBound": "0.05",
"filters": [
{
"minPrice": "556.80",
"maxPrice": "4529764",
"filterType": "PRICE_FILTER",
"tickSize": "0.10"
},
{
"stepSize": "0.001",
"filterType": "LOT_SIZE",
"maxQty": "1000",
"minQty": "0.001"
},
{
"stepSize": "0.001",
"filterType": "MARKET_LOT_SIZE",
"maxQty": "120",
"minQty": "0.001"
},
{
"limit": 200,
"filterType": "MAX_NUM_ORDERS"
},
{
"limit": 10,
"filterType": "MAX_NUM_ALGO_ORDERS"
},
{
"notional": "5",
"filterType": "MIN_NOTIONAL"
},
{
"multiplierDown": "0.9500",
"multiplierUp": "1.0500",
"multiplierDecimal": "4",
"filterType": "PERCENT_PRICE"
}
],
"orderTypes": [
"LIMIT",
"MARKET",
"STOP",
"STOP_MARKET",
"TAKE_PROFIT",
"TAKE_PROFIT_MARKET",
"TRAILING_STOP_MARKET"
],
"timeInForce": [
"GTC",
"IOC",
"FOK",
"GTX"
]
},
{
"symbol": "ETHUSDT",
"pair": "ETHUSDT",
"contractType": "PERPETUAL",
"deliveryDate": 4133404800000,
"onboardDate": 1569398400000,
"status": "TRADING",
"maintMarginPercent": "2.5000",
"requiredMarginPercent": "5.0000",
"baseAsset": "ETH",
"quoteAsset": "USDT",
"marginAsset": "USDT",
"pricePrecision": 2,
"quantityPrecision": 3,
"baseAssetPrecision": 8,
"quotePrecision": 8,
"underlyingType": "COIN",
"underlyingSubType": [
"Layer-1"
],
"settlePlan": 0,
"triggerProtect": "0.0500",
"liquidationFee": "0.015000",
"marketTakeBound": "0.05",
"filters": [
{
"minPrice": "39.86",
"maxPrice": "306177",
"filterType": "PRICE_FILTER",
"tickSize": "0.01"
},
{
"stepSize": "0.001",
"filterType": "LOT_SIZE",
"maxQty": "10000",
"minQty": "0.001"
},
{
"stepSize": "0.001",
"filterType": "MARKET_LOT_SIZE",
"maxQty": "2000",
"minQty": "0.001"
},
{
"limit": 200,
"filterType": "MAX_NUM_ORDERS"
},
{
"limit": 10,
"filterType": "MAX_NUM_ALGO_ORDERS"
},
{
"notional": "5",
"filterType": "MIN_NOTIONAL"
},
{
"multiplierDown": "0.9500",
"multiplierUp": "1.0500",
"multiplierDecimal": "4",
"filterType": "PERCENT_PRICE"
}
],
"orderTypes": [
"LIMIT",
"MARKET",
"STOP",
"STOP_MARKET",
"TAKE_PROFIT",
"TAKE_PROFIT_MARKET",
"TRAILING_STOP_MARKET"
],
"timeInForce": [
"GTC",
"IOC",
"FOK",
"GTX"
]
}
]
}
I want to get maxQty of MARKET_LOT_SIZE where symbol is BTCUSDT and contractType is PERPETUAL. What should i add more filter on this
For your requirement I suggest to create a class and use LINQ on top of that. This will help you in adding conditions quickly
Step1: use json2csharp to convert the json to C# Model
Step2:DeserializeObject using Newtonsoft.JsonConvert
Step3: Add LINQ to get desired output
//STEP2
var doc = JsonConvert.DeserializeObject<Root>(jsonData);
//STEP3
var maxQty = doc.symbols.Where(s => s.symbol == "BTCUSDT" && s.contractType == "PERPETUAL")
.SelectMany(x => x.filters)
.Where(y => y.filterType == "MARKET_LOT_SIZE")
.Max(x => x.maxQty);
//STEP1
public class Asset
{
public string asset { get; set; }
public bool marginAvailable { get; set; }
public string autoAssetExchange { get; set; }
}
public class Filter
{
public string minPrice { get; set; }
public string maxPrice { get; set; }
public string filterType { get; set; }
public string tickSize { get; set; }
public string stepSize { get; set; }
public string maxQty { get; set; }
public string minQty { get; set; }
public int? limit { get; set; }
public string notional { get; set; }
public string multiplierDown { get; set; }
public string multiplierUp { get; set; }
public string multiplierDecimal { get; set; }
}
public class RateLimit
{
public string rateLimitType { get; set; }
public string interval { get; set; }
public int intervalNum { get; set; }
public int limit { get; set; }
}
public class Root
{
public string timezone { get; set; }
public long serverTime { get; set; }
public string futuresType { get; set; }
public List<RateLimit> rateLimits { get; set; }
public List<object> exchangeFilters { get; set; }
public List<Asset> assets { get; set; }
public List<Symbol> symbols { get; set; }
}
public class Symbol
{
public string symbol { get; set; }
public string pair { get; set; }
public string contractType { get; set; }
public object deliveryDate { get; set; }
public object onboardDate { get; set; }
public string status { get; set; }
public string maintMarginPercent { get; set; }
public string requiredMarginPercent { get; set; }
public string baseAsset { get; set; }
public string quoteAsset { get; set; }
public string marginAsset { get; set; }
public int pricePrecision { get; set; }
public int quantityPrecision { get; set; }
public int baseAssetPrecision { get; set; }
public int quotePrecision { get; set; }
public string underlyingType { get; set; }
public List<string> underlyingSubType { get; set; }
public int settlePlan { get; set; }
public string triggerProtect { get; set; }
public string liquidationFee { get; set; }
public string marketTakeBound { get; set; }
public List<Filter> filters { get; set; }
public List<string> orderTypes { get; set; }
public List<string> timeInForce { get; set; }
}

Deserializing JSON with numbers as key

I have JSON like this:
{
"success": 1,
"method": "getTrades",
"5183": {
"buy_amount": "0.00455636",
"buy_currency": "BTC"
},
"6962": {
"buy_amount": "52.44700000",
"buy_currency": "IOT"
},
"6963": {
"buy_amount": "383.54300000",
"buy_currency": "TNT"
},
"6964": {
"buy_amount": "3412.50000000",
"buy_currency": "FUN"
},
"6965": {
"buy_amount": "539.45000000",
"buy_currency": "XLM"
}
}
I need to convert this JSON to domain model.
public class Root {
[JsonProperty("success")]
public long Success { get; set; }
[JsonProperty("method")]
public string Method { get; set; }
public Dictionary<long, Transaction> Transactions { get; set; }
public class Transaction{
[JsonProperty("buy_amount")]
public decimal? BuyAmount { get; set; }
[JsonProperty("buy_currency")]
public string BuyCurrency { get; set; }
var model = JsonConvert.DeserializeObject<Root>(response);
I created these two models, but when I try to deserialize transactions, they are null. I got data for success and method
Either the json needs to change, or you need to modify your c# structures. Not 100% sure, but based on the JSON, the c# class should be
public class Root : Dictionary<long, Transaction> {
[JsonProperty("success")]
public long Success { get; set; }
[JsonProperty("method")]
public string Method { get; set; }
Can you change the JSON to something like this?
{
"success": 1,
"method": "getTrades",
"transaction": [
{
"id": 5183,
"buy_amount": "0.00455636",
"buy_currency": "BTC"
},
{
"id": 6962,
"buy_amount": "52.44700000",
"buy_currency": "IOT"
},
{
"id": 6963,
"buy_amount": "383.54300000",
"buy_currency": "TNT"
},
{
"id": 6964,
"buy_amount": "3412.50000000",
"buy_currency": "FUN"
},
{
"id": 6965,
"buy_amount": "539.45000000",
"buy_currency": "XLM"
}
]
}
Then you could do something like that:
public class Transaction {
public int id { get; set; }
public string buy_amount { get; set; }
public string buy_currency { get; set; }
}
public class Root {
public int success { get; set; }
public string method { get; set; }
public List<Transaction> transaction { get; set; }
}

Merge and map from one class to another in C# using linq

I have a list of class like the below,
{
"Id": "ABCD",
"location": "ABCD Location",
"TypeId": "Mango",
"free": 3,
"total": 6
},
{
"locationId": "ABCD",
"location": "ABCD Location",
"deviceTypeId": "Apple",
"free": 4,
"total": 8
}
I want to map it to another class as below.
{
"locationId": "ABCD",
"location": "ABCD Location",
"Fruits":
{
Fruit:
{
TypeId: "Mango",
Free:"3",
Total: "6"
}
Fruit:
{
TypeId: "Apple",
Free:"4",
Total: "8"
}
}
}
How do I do merge and map the first class to another class using linq in c#?
You need something like below:
class Program
{
static void Main(string[] args)
{
List<class1> data = new List<class1>
{
new class1
{
Id= "ABCD",
location = "ABCD Location",
TypeId="Mango",
free=3,
total=6
},
new class1
{
Id="ABCD",
location="ABCD Location",
TypeId="Apple",
free=4,
total=8
}
};
var result = data.GroupBy(g => new
{
locationId = g.Id,
location = g.location
}).Select(s => new class2
{
locationId=s.Key.locationId,
location=s.Key.location,
Fruits=s.Select(f=>new Fruits
{
Free=f.free,
Total=f.total,
TypeId=f.TypeId
}).ToList()
}).ToList();
Console.ReadLine();
}
public class class1
{
public string Id { get; set; }
public string location { get; set; }
public string TypeId { get; set; }
public int free { get; set; }
public int total { get; set; }
}
public class class2
{
public string locationId { get; set; }
public string location { get; set; }
public string deviceTypeId { get; set; }
public List<Fruits> Fruits { get; set; }
}
public class Fruits
{
public string TypeId { get; set; }
public int Free { get; set; }
public int Total { get; set; }
}
}

json.net deserialization return null

I'm trying to deserialize a JSON string into a C# object. When I trap in the debugger, the JSON visualizer appears to be parsing the string just fine. However, when I push the string through the following code, the object returned has null values for the properties.
Here's my code:
public static Item GetPrices(string itemStr)
{
Item item = JsonConvert.DeserializeObject<Item>(itemStr);
return item;
}
public class Item
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "prices")]
public Prices Prices { get; set; }
}
public class Prices
{
[JsonProperty(PropertyName = "priceUofM")]
public PriceUofM[] PriceUofMs { get; set; }
}
public class PriceUofM
{
[JsonProperty(PropertyName = "uofm")]
public string UofM { get; set; }
[JsonProperty(PropertyName = "price")]
public string Price { get; set; }
}
and here's what I'm passing to it:
{
"item": {
"id": "1A50CC070S",
"prices":
[
{
"priceUofM": {
"uofm": "BOX",
"price": "$81.11"
}
},
{
"priceUofM": {
"uofm": "CASE",
"price": "$811.11"
}
}
]
}
}
I've run it through several online parsers, and all of them appear to be interpreting the JSON string just fine. What am I doing wrong in formatting the string to cause JsonConvert.DeserializeObject to fail?
Given this json:
{
"item": {
"id": "1A50CC070S",
"prices":
[
{
"priceUofM": {
"uofm": "BOX",
"price": "$81.11"
}
},
{
"priceUofM": {
"uofm": "CASE",
"price": "$811.11"
}
}
]
}
}
C# model would be:
public class Model
{
[JsonProperty("item")]
public Item Item { get; set; }
}
public class Item
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("prices")]
public List<Price> Prices { get; set; }
}
public class Price
{
[JsonProperty("priceUofM")]
public PriceUofM PriceUofM { get; set; }
}
public class PriceUofM
{
[JsonProperty("uofm")]
public string UofM { get; set; }
[JsonProperty("price")]
public string Price { get; set; }
}
In order to deserialize the string into an Item object, JSON string would be something like:
{
"id": "1A50CC070S",
"prices":
[
{
"priceUofM": {
"uofm": "BOX",
"price": "$81.11"
}
},
{
"priceUofM": {
"uofm": "CASE",
"price": "$811.11"
}
}
]
}

Categories

Resources