I have the following DTO:
class Permission
{
public string ObjectId { get; set; }
public string ObjectType { get; set; }
public string Scope { get; set; }
public string? AccountId { get; set; }
public string? GroupId { get; set; }
}
var permissions = new List<Permission>()
{
new(){ ObjectId = "1", ObjectType = "link", Scope = "link:read", AccountId = "1", GroupId = null },
new(){ ObjectId = "1", ObjectType = "link", Scope = "link:read", AccountId = "2", GroupId = null },
new(){ ObjectId = "1", ObjectType = "link", Scope = "link:read", AccountId = null, GroupId = "1" },
new(){ ObjectId = "1", ObjectType = "link", Scope = "link:write", AccountId = "2", GroupId = null },
new(){ ObjectId = "2", ObjectType = "link", Scope = "link:read", AccountId = "1", GroupId = null },
};
I want the following outcome:
{[
"1": {
"read": {
"accounts": ["1", "2"],
"groups": ["1", "2", "3"]
},
"write": {
"accounts": ["1", "2"],
"groups": ["1", "2", "3"]
}
}
]}
Basically an array of objects of Permission
, grouped by their ObjectId
property, and then grouped by each Scope
that contains an array of the AccountId
or GroupId
properties.
Each Permission
can have the same ObjectId
but different Scope
, AccountId
and GroupId
.
I tried to use GroupBy
but that gives me an IGrouping
and I'm not sure how to proceed.
CodePudding user response:
You need more than just nested group bys. In your output JSON you have keys as property names. You also need to use ToDictionary
to convert values into property keys.
var permissions = new List<Permission>()
{
new(){ ObjectId = "1", ObjectType = "link", Scope = "link:read", AccountId = "1", GroupId = null },
new(){ ObjectId = "1", ObjectType = "link", Scope = "link:read", AccountId = "2", GroupId = null },
new(){ ObjectId = "1", ObjectType = "link", Scope = "link:read", AccountId = null, GroupId = "1" },
new(){ ObjectId = "1", ObjectType = "link", Scope = "link:write", AccountId = "2", GroupId = null },
new(){ ObjectId = "2", ObjectType = "link", Scope = "link:read", AccountId = "1", GroupId = null },
};
var result = permissions.GroupBy(r=> r.ObjectId).Select(r=> new {
r.Key,
InnerGroups = r.GroupBy(q=> q.Scope.Replace("link:","")).Select(q=> new {
Scope = q.Key,
Accounts = q.Where(z=> z.AccountId != null).Select(z=> z.AccountId).ToArray(),
Groups = q.Where(z=> z.GroupId != null).Select(z=> z.GroupId).ToArray()
})
})
.ToDictionary(r=> r.Key,r=> r.InnerGroups.ToDictionary(q=> q.Scope,q=> new {q.Accounts,q.Groups}));
var serialized = JsonSerializer.Serialize(result,new JsonSerializerOptions{ WriteIndented=true });
Here is the output :
{
"1": {
"read": {
"Accounts": [
"1",
"2"
],
"Groups": [
"1"
]
},
"write": {
"Accounts": [
"2"
],
"Groups": []
}
},
"2": {
"read": {
"Accounts": [
"1"
],
"Groups": []
}
}
}
CodePudding user response:
You would have to use nested GroupBy
to achieve that and then convert the result to the dictionaries:
var result = permissions
.GroupBy(p => p.ObjectId)
.ToDictionary(g => g.Key, g => g.GroupBy(g => g.Scope)
.ToDictionary(g => g.Key, g => new
{
accounts = g.Select(per => per.AccountId).Distinct().ToList(),
groups = g.Select(per => per.GroupId).Distinct().ToList()
}));