Sorting JObject inside array by a field value










0















I have a JSON string like below:




"MetaData":
"ResourcesUsed": 1
,
"Result": [

"locations": [

"country": "Papua New Guinea",
"city": "Jacquinot Bay",
"locTypeAttributes":
"localDate": "2018-10-08T04:21:00-07:00",
"utcDate": "2018-10-08T04:21:00-07:00",
,
"point":
"coordinates": [
151.52,
-5.6
],
"type": "Point"

,
"country": "Papua New Guinea2",
"city": "Jacquinot Bay2",
"locTypeAttributes":
"localDate": "2018-10-08T04:21:00-07:00",
"utcDate": "2018-10-02T04:21:00-07:00",
,
"point":
"coordinates": [
151.52,
-5.6
],
"type": "Point"


]

]



I converted it to a JSON object using Newtonsoft. What I want to do is to sort the locations array(s) inside the Result array by the utcDate field nested in each locations item. I found the following thread: C# Sort JSON string keys. However, I could not still implement it since I have arrays inside my object, while that question deals purely with sorting objects inside objects alphabetically by property name.



Here is a piece of code that I wrote so far:



public string GenerateJson()

var model = (JObject)JsonConvert.DeserializeObject(data);
Sort(model);

private void Sort(JObject jObj)

var props = jObj["Result"][0]["locations"].ToList();
foreach (var prop in props)

prop.Remove();


foreach (var prop in props.OrderBy(p => p.Name))

jObj.Add(prop);
if (prop.Value is JObject)
Sort((JObject)prop.Value);
if (prop.Value is JArray)

Int32 iCount = prop.Value.Count();
for (Int32 iIterator = 0; iIterator < iCount; iIterator++)
if (prop.Value[iIterator] is JObject)
Sort((JObject)prop.Value[iIterator]);












share|improve this question
























  • Why not deserialize to a custom class and then sort it (normally)

    – Make StackOverflow Good Again
    Nov 15 '18 at 20:05











  • @Disaffected1070452 that's my last resort, I was trying to avoid creating any custom class.

    – DeadlyDagger
    Nov 15 '18 at 20:08












  • Do you want to sort the "Result": array, or do you want to sort each "Result[*].locations" array? Because the locations themselves are an array so there might in principle be more than one, each with its own utcDate. And if you do want to sort the "Results" array how do you want to deal with the situation where a result has multiple locations with multiple utcDate values? C# Sort JSON string keys is for recursively sorting a tree of objects by property name so it doesn't really apply here.

    – dbc
    Nov 15 '18 at 20:38












  • @dbc I just simplified the JSON string, so in Result, we will always have one array of locations, I want to sort that array by utcDate.

    – DeadlyDagger
    Nov 15 '18 at 21:19















0















I have a JSON string like below:




"MetaData":
"ResourcesUsed": 1
,
"Result": [

"locations": [

"country": "Papua New Guinea",
"city": "Jacquinot Bay",
"locTypeAttributes":
"localDate": "2018-10-08T04:21:00-07:00",
"utcDate": "2018-10-08T04:21:00-07:00",
,
"point":
"coordinates": [
151.52,
-5.6
],
"type": "Point"

,
"country": "Papua New Guinea2",
"city": "Jacquinot Bay2",
"locTypeAttributes":
"localDate": "2018-10-08T04:21:00-07:00",
"utcDate": "2018-10-02T04:21:00-07:00",
,
"point":
"coordinates": [
151.52,
-5.6
],
"type": "Point"


]

]



I converted it to a JSON object using Newtonsoft. What I want to do is to sort the locations array(s) inside the Result array by the utcDate field nested in each locations item. I found the following thread: C# Sort JSON string keys. However, I could not still implement it since I have arrays inside my object, while that question deals purely with sorting objects inside objects alphabetically by property name.



Here is a piece of code that I wrote so far:



public string GenerateJson()

var model = (JObject)JsonConvert.DeserializeObject(data);
Sort(model);

private void Sort(JObject jObj)

var props = jObj["Result"][0]["locations"].ToList();
foreach (var prop in props)

prop.Remove();


foreach (var prop in props.OrderBy(p => p.Name))

jObj.Add(prop);
if (prop.Value is JObject)
Sort((JObject)prop.Value);
if (prop.Value is JArray)

Int32 iCount = prop.Value.Count();
for (Int32 iIterator = 0; iIterator < iCount; iIterator++)
if (prop.Value[iIterator] is JObject)
Sort((JObject)prop.Value[iIterator]);












share|improve this question
























  • Why not deserialize to a custom class and then sort it (normally)

    – Make StackOverflow Good Again
    Nov 15 '18 at 20:05











  • @Disaffected1070452 that's my last resort, I was trying to avoid creating any custom class.

    – DeadlyDagger
    Nov 15 '18 at 20:08












  • Do you want to sort the "Result": array, or do you want to sort each "Result[*].locations" array? Because the locations themselves are an array so there might in principle be more than one, each with its own utcDate. And if you do want to sort the "Results" array how do you want to deal with the situation where a result has multiple locations with multiple utcDate values? C# Sort JSON string keys is for recursively sorting a tree of objects by property name so it doesn't really apply here.

    – dbc
    Nov 15 '18 at 20:38












  • @dbc I just simplified the JSON string, so in Result, we will always have one array of locations, I want to sort that array by utcDate.

    – DeadlyDagger
    Nov 15 '18 at 21:19













0












0








0








I have a JSON string like below:




"MetaData":
"ResourcesUsed": 1
,
"Result": [

"locations": [

"country": "Papua New Guinea",
"city": "Jacquinot Bay",
"locTypeAttributes":
"localDate": "2018-10-08T04:21:00-07:00",
"utcDate": "2018-10-08T04:21:00-07:00",
,
"point":
"coordinates": [
151.52,
-5.6
],
"type": "Point"

,
"country": "Papua New Guinea2",
"city": "Jacquinot Bay2",
"locTypeAttributes":
"localDate": "2018-10-08T04:21:00-07:00",
"utcDate": "2018-10-02T04:21:00-07:00",
,
"point":
"coordinates": [
151.52,
-5.6
],
"type": "Point"


]

]



I converted it to a JSON object using Newtonsoft. What I want to do is to sort the locations array(s) inside the Result array by the utcDate field nested in each locations item. I found the following thread: C# Sort JSON string keys. However, I could not still implement it since I have arrays inside my object, while that question deals purely with sorting objects inside objects alphabetically by property name.



Here is a piece of code that I wrote so far:



public string GenerateJson()

var model = (JObject)JsonConvert.DeserializeObject(data);
Sort(model);

private void Sort(JObject jObj)

var props = jObj["Result"][0]["locations"].ToList();
foreach (var prop in props)

prop.Remove();


foreach (var prop in props.OrderBy(p => p.Name))

jObj.Add(prop);
if (prop.Value is JObject)
Sort((JObject)prop.Value);
if (prop.Value is JArray)

Int32 iCount = prop.Value.Count();
for (Int32 iIterator = 0; iIterator < iCount; iIterator++)
if (prop.Value[iIterator] is JObject)
Sort((JObject)prop.Value[iIterator]);












share|improve this question
















I have a JSON string like below:




"MetaData":
"ResourcesUsed": 1
,
"Result": [

"locations": [

"country": "Papua New Guinea",
"city": "Jacquinot Bay",
"locTypeAttributes":
"localDate": "2018-10-08T04:21:00-07:00",
"utcDate": "2018-10-08T04:21:00-07:00",
,
"point":
"coordinates": [
151.52,
-5.6
],
"type": "Point"

,
"country": "Papua New Guinea2",
"city": "Jacquinot Bay2",
"locTypeAttributes":
"localDate": "2018-10-08T04:21:00-07:00",
"utcDate": "2018-10-02T04:21:00-07:00",
,
"point":
"coordinates": [
151.52,
-5.6
],
"type": "Point"


]

]



I converted it to a JSON object using Newtonsoft. What I want to do is to sort the locations array(s) inside the Result array by the utcDate field nested in each locations item. I found the following thread: C# Sort JSON string keys. However, I could not still implement it since I have arrays inside my object, while that question deals purely with sorting objects inside objects alphabetically by property name.



Here is a piece of code that I wrote so far:



public string GenerateJson()

var model = (JObject)JsonConvert.DeserializeObject(data);
Sort(model);

private void Sort(JObject jObj)

var props = jObj["Result"][0]["locations"].ToList();
foreach (var prop in props)

prop.Remove();


foreach (var prop in props.OrderBy(p => p.Name))

jObj.Add(prop);
if (prop.Value is JObject)
Sort((JObject)prop.Value);
if (prop.Value is JArray)

Int32 iCount = prop.Value.Count();
for (Int32 iIterator = 0; iIterator < iCount; iIterator++)
if (prop.Value[iIterator] is JObject)
Sort((JObject)prop.Value[iIterator]);









c# json sorting json.net






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 15 '18 at 22:44









dbc

55.4k875130




55.4k875130










asked Nov 15 '18 at 19:29









DeadlyDaggerDeadlyDagger

255




255












  • Why not deserialize to a custom class and then sort it (normally)

    – Make StackOverflow Good Again
    Nov 15 '18 at 20:05











  • @Disaffected1070452 that's my last resort, I was trying to avoid creating any custom class.

    – DeadlyDagger
    Nov 15 '18 at 20:08












  • Do you want to sort the "Result": array, or do you want to sort each "Result[*].locations" array? Because the locations themselves are an array so there might in principle be more than one, each with its own utcDate. And if you do want to sort the "Results" array how do you want to deal with the situation where a result has multiple locations with multiple utcDate values? C# Sort JSON string keys is for recursively sorting a tree of objects by property name so it doesn't really apply here.

    – dbc
    Nov 15 '18 at 20:38












  • @dbc I just simplified the JSON string, so in Result, we will always have one array of locations, I want to sort that array by utcDate.

    – DeadlyDagger
    Nov 15 '18 at 21:19

















  • Why not deserialize to a custom class and then sort it (normally)

    – Make StackOverflow Good Again
    Nov 15 '18 at 20:05











  • @Disaffected1070452 that's my last resort, I was trying to avoid creating any custom class.

    – DeadlyDagger
    Nov 15 '18 at 20:08












  • Do you want to sort the "Result": array, or do you want to sort each "Result[*].locations" array? Because the locations themselves are an array so there might in principle be more than one, each with its own utcDate. And if you do want to sort the "Results" array how do you want to deal with the situation where a result has multiple locations with multiple utcDate values? C# Sort JSON string keys is for recursively sorting a tree of objects by property name so it doesn't really apply here.

    – dbc
    Nov 15 '18 at 20:38












  • @dbc I just simplified the JSON string, so in Result, we will always have one array of locations, I want to sort that array by utcDate.

    – DeadlyDagger
    Nov 15 '18 at 21:19
















Why not deserialize to a custom class and then sort it (normally)

– Make StackOverflow Good Again
Nov 15 '18 at 20:05





Why not deserialize to a custom class and then sort it (normally)

– Make StackOverflow Good Again
Nov 15 '18 at 20:05













@Disaffected1070452 that's my last resort, I was trying to avoid creating any custom class.

– DeadlyDagger
Nov 15 '18 at 20:08






@Disaffected1070452 that's my last resort, I was trying to avoid creating any custom class.

– DeadlyDagger
Nov 15 '18 at 20:08














Do you want to sort the "Result": array, or do you want to sort each "Result[*].locations" array? Because the locations themselves are an array so there might in principle be more than one, each with its own utcDate. And if you do want to sort the "Results" array how do you want to deal with the situation where a result has multiple locations with multiple utcDate values? C# Sort JSON string keys is for recursively sorting a tree of objects by property name so it doesn't really apply here.

– dbc
Nov 15 '18 at 20:38






Do you want to sort the "Result": array, or do you want to sort each "Result[*].locations" array? Because the locations themselves are an array so there might in principle be more than one, each with its own utcDate. And if you do want to sort the "Results" array how do you want to deal with the situation where a result has multiple locations with multiple utcDate values? C# Sort JSON string keys is for recursively sorting a tree of objects by property name so it doesn't really apply here.

– dbc
Nov 15 '18 at 20:38














@dbc I just simplified the JSON string, so in Result, we will always have one array of locations, I want to sort that array by utcDate.

– DeadlyDagger
Nov 15 '18 at 21:19





@dbc I just simplified the JSON string, so in Result, we will always have one array of locations, I want to sort that array by utcDate.

– DeadlyDagger
Nov 15 '18 at 21:19












1 Answer
1






active

oldest

votes


















0














You can sort each individual "Result[*].locations" array using LINQ as follows:



// Load the JSON without parsing or converting any dates.
var model = JsonConvert.DeserializeObject<JObject>(data, new JsonSerializerSettings DateParseHandling = DateParseHandling.None );

// Construct a serializer that converts all DateTime values to UTC
var serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings DateTimeZoneHandling = DateTimeZoneHandling.Utc );

foreach (var locations in model.SelectTokens("Result[*].locations").OfType<JArray>())

// Then sort the locations by utcDate converting the value to UTC at this time.
var query = from location in locations
let utcDate = location.SelectToken("locTypeAttributes.utcDate").ToObject<DateTime>(serializer)
orderby utcDate
select location;
locations.ReplaceAll(query.ToList());



Notes:




  • The JSON is initially loaded using DateParseHandling.None to prevent the "localDate" and "utcDate" strings from being prematurely interpreted as DateTime objects with a uniform DateTime.Kind.



    (For a discussion of how Json.NET interprets strings that look like dates, see Serializing Dates in JSON.)



  • We then iterate through all "locations" arrays using SelectTokens("Result[*].locations") where [*] is the JSONPath wildcard character, selecting all entries in the "Results" array.


  • We then order each "locations" array by deserializing the nested locTypeAttributes.utcDate to a UTC date, then ordering using LINQ.


  • Finally the array is updated using JArray.ReplaceAll().


  • If any locTypeAttributes.utcDate property is missing, an exception will be thrown. You could instead deserialize to DateTime? if that is a possibility.


Working sample .Net fiddle here.






share|improve this answer
























    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53326681%2fsorting-jobject-inside-array-by-a-field-value%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    You can sort each individual "Result[*].locations" array using LINQ as follows:



    // Load the JSON without parsing or converting any dates.
    var model = JsonConvert.DeserializeObject<JObject>(data, new JsonSerializerSettings DateParseHandling = DateParseHandling.None );

    // Construct a serializer that converts all DateTime values to UTC
    var serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings DateTimeZoneHandling = DateTimeZoneHandling.Utc );

    foreach (var locations in model.SelectTokens("Result[*].locations").OfType<JArray>())

    // Then sort the locations by utcDate converting the value to UTC at this time.
    var query = from location in locations
    let utcDate = location.SelectToken("locTypeAttributes.utcDate").ToObject<DateTime>(serializer)
    orderby utcDate
    select location;
    locations.ReplaceAll(query.ToList());



    Notes:




    • The JSON is initially loaded using DateParseHandling.None to prevent the "localDate" and "utcDate" strings from being prematurely interpreted as DateTime objects with a uniform DateTime.Kind.



      (For a discussion of how Json.NET interprets strings that look like dates, see Serializing Dates in JSON.)



    • We then iterate through all "locations" arrays using SelectTokens("Result[*].locations") where [*] is the JSONPath wildcard character, selecting all entries in the "Results" array.


    • We then order each "locations" array by deserializing the nested locTypeAttributes.utcDate to a UTC date, then ordering using LINQ.


    • Finally the array is updated using JArray.ReplaceAll().


    • If any locTypeAttributes.utcDate property is missing, an exception will be thrown. You could instead deserialize to DateTime? if that is a possibility.


    Working sample .Net fiddle here.






    share|improve this answer





























      0














      You can sort each individual "Result[*].locations" array using LINQ as follows:



      // Load the JSON without parsing or converting any dates.
      var model = JsonConvert.DeserializeObject<JObject>(data, new JsonSerializerSettings DateParseHandling = DateParseHandling.None );

      // Construct a serializer that converts all DateTime values to UTC
      var serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings DateTimeZoneHandling = DateTimeZoneHandling.Utc );

      foreach (var locations in model.SelectTokens("Result[*].locations").OfType<JArray>())

      // Then sort the locations by utcDate converting the value to UTC at this time.
      var query = from location in locations
      let utcDate = location.SelectToken("locTypeAttributes.utcDate").ToObject<DateTime>(serializer)
      orderby utcDate
      select location;
      locations.ReplaceAll(query.ToList());



      Notes:




      • The JSON is initially loaded using DateParseHandling.None to prevent the "localDate" and "utcDate" strings from being prematurely interpreted as DateTime objects with a uniform DateTime.Kind.



        (For a discussion of how Json.NET interprets strings that look like dates, see Serializing Dates in JSON.)



      • We then iterate through all "locations" arrays using SelectTokens("Result[*].locations") where [*] is the JSONPath wildcard character, selecting all entries in the "Results" array.


      • We then order each "locations" array by deserializing the nested locTypeAttributes.utcDate to a UTC date, then ordering using LINQ.


      • Finally the array is updated using JArray.ReplaceAll().


      • If any locTypeAttributes.utcDate property is missing, an exception will be thrown. You could instead deserialize to DateTime? if that is a possibility.


      Working sample .Net fiddle here.






      share|improve this answer



























        0












        0








        0







        You can sort each individual "Result[*].locations" array using LINQ as follows:



        // Load the JSON without parsing or converting any dates.
        var model = JsonConvert.DeserializeObject<JObject>(data, new JsonSerializerSettings DateParseHandling = DateParseHandling.None );

        // Construct a serializer that converts all DateTime values to UTC
        var serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings DateTimeZoneHandling = DateTimeZoneHandling.Utc );

        foreach (var locations in model.SelectTokens("Result[*].locations").OfType<JArray>())

        // Then sort the locations by utcDate converting the value to UTC at this time.
        var query = from location in locations
        let utcDate = location.SelectToken("locTypeAttributes.utcDate").ToObject<DateTime>(serializer)
        orderby utcDate
        select location;
        locations.ReplaceAll(query.ToList());



        Notes:




        • The JSON is initially loaded using DateParseHandling.None to prevent the "localDate" and "utcDate" strings from being prematurely interpreted as DateTime objects with a uniform DateTime.Kind.



          (For a discussion of how Json.NET interprets strings that look like dates, see Serializing Dates in JSON.)



        • We then iterate through all "locations" arrays using SelectTokens("Result[*].locations") where [*] is the JSONPath wildcard character, selecting all entries in the "Results" array.


        • We then order each "locations" array by deserializing the nested locTypeAttributes.utcDate to a UTC date, then ordering using LINQ.


        • Finally the array is updated using JArray.ReplaceAll().


        • If any locTypeAttributes.utcDate property is missing, an exception will be thrown. You could instead deserialize to DateTime? if that is a possibility.


        Working sample .Net fiddle here.






        share|improve this answer















        You can sort each individual "Result[*].locations" array using LINQ as follows:



        // Load the JSON without parsing or converting any dates.
        var model = JsonConvert.DeserializeObject<JObject>(data, new JsonSerializerSettings DateParseHandling = DateParseHandling.None );

        // Construct a serializer that converts all DateTime values to UTC
        var serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings DateTimeZoneHandling = DateTimeZoneHandling.Utc );

        foreach (var locations in model.SelectTokens("Result[*].locations").OfType<JArray>())

        // Then sort the locations by utcDate converting the value to UTC at this time.
        var query = from location in locations
        let utcDate = location.SelectToken("locTypeAttributes.utcDate").ToObject<DateTime>(serializer)
        orderby utcDate
        select location;
        locations.ReplaceAll(query.ToList());



        Notes:




        • The JSON is initially loaded using DateParseHandling.None to prevent the "localDate" and "utcDate" strings from being prematurely interpreted as DateTime objects with a uniform DateTime.Kind.



          (For a discussion of how Json.NET interprets strings that look like dates, see Serializing Dates in JSON.)



        • We then iterate through all "locations" arrays using SelectTokens("Result[*].locations") where [*] is the JSONPath wildcard character, selecting all entries in the "Results" array.


        • We then order each "locations" array by deserializing the nested locTypeAttributes.utcDate to a UTC date, then ordering using LINQ.


        • Finally the array is updated using JArray.ReplaceAll().


        • If any locTypeAttributes.utcDate property is missing, an exception will be thrown. You could instead deserialize to DateTime? if that is a possibility.


        Working sample .Net fiddle here.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 16 '18 at 0:44

























        answered Nov 15 '18 at 22:38









        dbcdbc

        55.4k875130




        55.4k875130





























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53326681%2fsorting-jobject-inside-array-by-a-field-value%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Top Tejano songwriter Luis Silva dead of heart attack at 64

            政党

            天津地下鉄3号線