Search code examples
c#jsonlinqjson.net

Using LINQ in JArray


I have a JSON

{
  "departments": [
    {
      "2": {"city": "Petersburg", "employees": "1200"}
    },
    {
      "1": {"city": "Ekaterinburg", "employees": "4000"}
    }
  ]
}

How can I get the value of the city, if I know an ID using LINQ or something else?

I tried

var id = 2;
json["departments"].Single(x=>x.Name==id.ToString())["city"];

But it doesn't work, I get a compilation error:

'JToken' does not contain a definition for 'Name' and no accessible extension method 'Name' accepting a first argument of type 'JToken' could be found (are you missing a using directive or an assembly reference?)

Demo fiddle here.


Solution

  • Your LINQ query can be implemented as follows:

    var id = "2";
    var city = (string)json["departments"]
        .Where(o => o[id] != null) // From the departments array, select the object where the required id property exists
        .Select(o => o[id]["city"]).SingleOrDefault(); // An extract the value of "city" from the nested object.
    

    Or, equivalently:

    var id = "2";
    var city = (string)json["departments"]
        .SelectMany(i => i) // Use SelectMany() to project the properties of the array items to a flat enumerable 
        .Cast<JProperty>()  // Cast them to JProperty
        .Where(p => p.Name == id) // Now you can use Name
        .Select(p => p.Value["city"])
        .SingleOrDefault();
    

    Alternatively, you could use SelectToken() for this purpose:

    var id = "2";
    var path = $"departments[*].{id}.city"; // departments[*].2.city
    var city = (string)json.SelectToken(path);
    

    SelectToken() supports JSONPath syntax, and [*] is the JSONPath wildcard operator indicating that all array items should be searched.

    Demo fiddle here.