1

Hoping someone can help me out here or at least point me in the right direction. I have spent hours trying to get this sorted and I am lost.

The code below is just mock, my actual json is returned via AJAX using jquery. My problem is not sorting, but sorting on a nested json object.

I am trying to sort the json output based on cost. (lowest cost to highest), my attempts have failed and I cannot get this sorted. I keep getting "sort" is undefined.

Any help would be appreciated or if you can just point out what I am doing wrong here.

var json = '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';

    /* 

    This doesnt work and returns undefined. 
    
    json["shipping_method"]["quote"].sort(function(a, b) {
        return a['cost'] > b['cost'];
      });

    // I found this example, but also didn't work.
    custSort = (prop1, prop2 = null, direction = 'asc') => (e1, e2) => {
    const a = prop2 ? e1[prop1][prop2] : e1[prop1],
    b = prop2 ? e2[prop1][prop2] : e2[prop1],
    sortOrder = direction === "asc" ? 1 : -1
     return (a < b) ? -sortOrder : (a > b) ? //sortOrder : 0;
    };      

   json.sort(custSort("quote", "cost", "desc"));*/


json = JSON.parse(json);

for (var i in json["shipping_method"]) {

  // EDIT::  I want the sorting to occur here if possible. 

  for (j in json["shipping_method"][i]["quote"]) {


  //EDIT::  I want to keep this for loop, but with the results sorted by cost 

    console.log(json["shipping_method"][i]["quote"][j]["cost"]);

  }

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

3
  • What are you trying to accomplish? Based on what I see, it looks like you're trying to sort something based on 'cost', but it isn't an array. What do you expect the result to look like? Commented Mar 6, 2020 at 5:43
  • sort() is a function for arrays not objects. Is the actual response in the same format as your json mockup? If it is then you could add the content of quote into an array then just use the sort() function. Commented Mar 6, 2020 at 5:46
  • I didn't got what is point of sorting objects, can you please add the expected result in your question . What is the result expected from after sorting Commented Mar 6, 2020 at 6:52

5 Answers 5

4

Convert Object to Sorted Array

The object can be flattened out so that parent keys are included in the deep object as it's been iterated over. An early example to that can be found in this answers edit history. It has been removed since information like the quote-id was not deemed important.

Below is an example of using Object.values, which traverses an object and only returns an array of that objects values (discarding the keys). The values can then be sorted as intended, by cost.

const json = JSON.parse(getData());

for (let method in json["shipping_method"]) {
  // cache
  let quotes = json['shipping_method'][method]['quote']
  
  // convert object to array and sort
  let sortedQuotes = Object.values(quotes).sort((a, b)=>a.cost-b.cost);
  
  console.log(sortedQuotes)
}


/* Dummy Data */
function getData() {
  return '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
}
.as-console-wrapper {
  max-height: 100vh !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Quotes by Cost per Shipping Method

This assumes that the quote ID is needed (perhaps to be placed on a row); otherwise this can be simplified using Object.values in place of Object.entries (amongst other changes).

Disregard what the output function is doing. It is a quick example, that doesn't ensure proper cell order and has a host of other limitations and vulnerabilities. It is only used to demonstrate that the original quote data is still available after sorting.

const data = JSON.parse(getData());

for (let method in data.shipping_method) {
  output({row: method}, {class:'capitalize'})
  
  // cache
  let quotes = data.shipping_method[method].quote
  let sortContent = Object.entries(quotes);
  let sortedQuotes = sortContent.sort((a,b)=>a[1].cost-b[1].cost).map(i=>i[0]);
  
  for (let quoteId of sortedQuotes){
    let quoteInfo = quotes[quoteId];
    output({cell: quoteInfo})
  }
}

/* Dummy Data */
function getData() {
  return '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
}

/* Really simple output for demo purpose */
function output(data, options={}){

  if ('row' in data){
    let $col = $('<td></td>', options).html(data.row)
    let $row = $('<tr></tr>').append($col);
    $('tbody').append( $row )
  }
  
  else if ('cell' in data){
    let $row = $('<tr></tr>')
    for( let key in data.cell ){
      let $col = $('<td></td>', options).html(data.cell[key])
      $row.append($col)
    }
    $('tbody').append( $row )
  }
  
}
.capitalize {
  text-transform: uppercase;
}

td {
  min-width: 5rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<table>
  <thead></thead>
  <tbody></tbody>
</table>

Sign up to request clarification or add additional context in comments.

4 Comments

This is good. Any idea how I would convert back into an object though? I need to keep that original for loop.. What I posted was just mock code the actual code is outputting a table, etc. I updated my post.
@limit the object still exists; perform console.log(json) and you'll see it is in its natural form with two additional keys. You can use sortedQuote[index].quote_id for the ordering. I'll show you a demonstration of what I think you're after (sorted quotes by costs for shipping method)
Awesome. Very much appreciated. Great examples as well. Thank you very much for this.
Great solution and patient explanation. The core answer seems to be Object.values(quotes).sort((a, b)=>a.cost-b.cost) though I'm not clear on what a.cost-b.cost is doing. ?
1

Your objects can have any amount of properties and you can choose to sort by whatever object property you want, number or string, if you put the objects in an array.

var item = JSON.parse(json).shipping_method.ups.quote;

Use Object.values() to get array of values of the JSON object and then use slice() method to copy the array of JSON objects and not just make a reference.

var byCost = Object.values(item).slice(0);

Finally you can use sort function for that array of objects.

byCost.sort(function(a,b) {return a.cost - b.cost});

var json = '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
var item = JSON.parse(json).shipping_method.ups.quote;
var byCost = Object.values(item).slice(0);
byCost.sort(function(a,b) {return a.cost - b.cost});
console.log(byCost)

Comments

0

It doesn't seem like you are accessing the right path here... Looking at the JSON you posted you should be attempting to sort shipping_method.ups.quote its also worth noting that shipping_method.ups.quote is an object and must be converted to an Array to invoke .sort as this method lives on the Array prototype.

This can be done several ways but Object.values() is one such way.

Comments

0

you may try the following,

json = JSON.parse(json);
  let item = json.shipping_method.ups.quote,
    temp = [];
  for (let key in item) {
    temp.push(item[key]);
  }
  temp.sort((x, y) => x.cost - y.cost);
  json.shipping_method.ups.quote = temp;

converting your object into array and then sort;

Comments

0

As i can see , your problem is to sort the object with cost as their keys should stays same ,

try out this ,

var json = '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';

var json = JSON.parse(json);
let data = []
for(var i in json.shipping_method.ups.quote){
    data.push(json.shipping_method.ups.quote[i])
    data.sort((a,b) => a.cost - b.cost);
}

This create those key agains as they are before

let final = {} ;
data.forEach(el => final[el.code.split('.')[1]] = el);

Finally update the qoute with the latest sorted quotes :

json.shipping_method.ups.quote = final;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.