LINQ to JSON - запрос массива
Мне нужно выбрать пользователей, которые имеют "3" в своем массиве json.
{
"People":[
{
"id" : "123",
"firstName" : "Bill",
"lastName" : "Gates",
"roleIds" : {
"int" : ["3", "9", "1"]
}
},
{
"id" : "456",
"firstName" : "Steve",
"lastName" : "Jobs",
"roleIds" : {
"int" : ["3", "1"]
}
},
{
"id" : "789",
"firstName" : "Elon",
"lastName" : "Musk",
"roleIds" : {
"int" : ["3", "7"]
}
},
{
"id" : "012",
"firstName" : "Agatha",
"lastName" : "Christie",
"roleIds" : {
"int" : "2"
}
}
]}
В конце концов, мои результаты должны быть Элон Маск и Стив Джобс. Это код, который я использовал (и другие варианты):
var roleIds = pplFeed["People"]["roleIds"].Children()["int"].Values<string>();
var resAnAssocInfo = pplFeed["People"]
.Where(p => p["roleIds"].Children()["int"].Values<string>().Contains("3"))
.Select(p => new
{
id = p["id"],
FName = p["firstName"],
LName = p["lastName"]
}).ToList();
Я получаю следующую ошибку:
"Accessed JArray values with invalid key value: "roleIds". Int32 array index expected"
Я изменился .Values<string>()
в .Values<int>()
и до сих пор не повезло.
Что я делаю неправильно?
2 ответа
Вы довольно близко Измени свой Where
пункт из этого:
.Where(p => p["roleIds"].Children()["int"].Values<string>().Contains("3"))
к этому:
.Where(p => p["roleIds"]["int"].Children().Contains("3"))
и вы получите желаемый результат (хотя в ваших примерах данных фактически есть три пользователя с идентификатором роли "3"
а не два).
Однако есть еще одна проблема, с которой вы можете столкнуться, и этот код все равно не будет работать. Вы заметите, что для Агаты Кристи ценность int
это не массив, как другие, это простая строка. Если значение иногда будет массивом, а иногда нет, тогда вам нужно предложение where, которое может обрабатывать оба. Примерно так должно работать:
.Where(p => p["roleIds"]["int"].Children().Contains(roleId) ||
p["roleIds"]["int"].ToString() == roleId)
...где roleId
это строка, содержащая идентификатор, который вы ищете.
Скрипка: https://dotnetfiddle.net/Zr1b6R
Проблема в том, что не все объекты используют один и тот же интерфейс. Последний элемент в этом списке имеет одно строковое значение в roleIds.int
свойство, в то время как все остальные имеют массив. Вам необходимо нормализовать это свойство, а затем выполнить проверку. Будет проще, если они все будут массивами.
Вы должны быть в состоянии сделать это:
var roleId = "3";
var query =
from p in pplFeed["People"]
let roleIds = p.SelectToken("roleIds.int")
let normalized = roleIds.Type == JTokenType.Array ? roleIds : new JArray(roleIds)
where normalized.Values().Contains(roleId)
select new
{
id = p["id"],
FName = p["firstName"],
LName = p["lastName"],
};