Search code examples
linqjson.netlinq-to-json

LINQ to JSON - Querying an array


I need to select users that have a "3" in their json array.

{
    "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"
        }
    }
]}

In the end, my results should be Elon Musk & Steve Jobs. This is the code that I used (& other variations):

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();

I'm getting the following error:

"Accessed JArray values with invalid key value: "roleIds".  Int32 array index expected"

I changed .Values<string>() to .Values<int>() and still no luck.

What am I doing wrong?


Solution

  • You are pretty close. Change your Where clause from this:

    .Where(p => p["roleIds"].Children()["int"].Values<string>().Contains("3"))
    

    to this:

    .Where(p => p["roleIds"]["int"].Children().Contains("3"))
    

    and you will get you the result you want (although there are actually three users in your sample data with a role id of "3", not two).

    However, there's another issue that you might hit for which this code still won't work. You'll notice that for Agatha Christie, the value of int is not an array like the others, it is a simple string. If the value will sometimes be an array and sometimes not, then you need a where clause that can handle both. Something like this should work:

    .Where(p => p["roleIds"]["int"].Children().Contains(roleId) ||
                p["roleIds"]["int"].ToString() == roleId)
    

    ...where roleId is a string containing the id you are looking for.

    Fiddle: https://dotnetfiddle.net/Zr1b6R