7

Given the following data structure:

var MyData = [
  {"id": 1, "status": "live", dateCreated: "12:00:00 01/02/2016"}, 
  {"id": 2, "status": "draft", dateCreated: "13:00:00 03/12/2015"}, 
  {"id": 3, "status": "ready", dateCreated: "16:00:00 04/09/2016"}, 
  {"id": 4, "status": "ready", dateCreated: "10:00:00 01/10/2016"}, 
  {"id": 5, "status": "live", dateCreated: "09:00:00 05/07/2015"}, 
  {"id": 6, "status": "draft", dateCreated: "08:00:00 11/03/2016"}, 
  {"id": 7, "status": "ready", dateCreated: "20:00:00 12/02/2016"}
]

I'm trying to sort and group it into these conditions:

  1. Grouped by status
  2. Ordered by status such that the order is "live", "draft", "ready"
  3. Items within each status should be ordered by dateCreated, most recent first.

What I have so far:

// this object will help us define our custom order as it's not alphabetical
const itemOrder = {
  'live': 1, 
  'ready': 2,
  'draft': 3
};

const sortByStatus = (statusA, statusB) => {
  if ( itemOrder[statusA] > itemOrder[statusB] ) return 1;
  if ( itemOrder[statusA] < itemOrder[statusB] ) return -1;
  return 0;
};

return List(MyData)
  .groupBy(item => item.status)
  .sort( sortByStatus )

Ignore for a moment the fact that I've not got to the point where I can sort by date yet :)

The problem with the above seems to be that sortByStatus is being passed the IndexedIterable that is the overall group but not it's key so I can't sort it by that key. I think I probably need to use sortBy but the Immutable.js docs are incomprehensible and have no examples on which to work out how to achieve this.

So, the question: how can I take the result of the groupBy action and sort it into a custom order and additionally how can I ensure that all the items in each group are sorted by date?

slashwhatever
  • 732
  • 8
  • 24
  • For help sorting by date, see this answer: https://stackoverflow.com/questions/46936825/how-can-i-sort-an-immutablejs-list-object-on-multiple-keys – KerSplosh Nov 13 '17 at 15:53

2 Answers2

3

One easy fix is to just reach in to the first item of the array and get the status from there:

var MyData = [
  {"id": 1, "status": "live", dateCreated: "12:00:00 01/02/2016"}, 
  {"id": 2, "status": "draft", dateCreated: "13:00:00 03/12/2015"}, 
  {"id": 3, "status": "ready", dateCreated: "16:00:00 04/09/2016"}, 
  {"id": 4, "status": "ready", dateCreated: "10:00:00 01/10/2016"}, 
  {"id": 5, "status": "live", dateCreated: "09:00:00 05/07/2015"}, 
  {"id": 6, "status": "draft", dateCreated: "08:00:00 11/03/2016"}, 
  {"id": 7, "status": "ready", dateCreated: "20:00:00 12/02/2016"}
]

const itemOrder = {
  'live': 1, 
  'ready': 2,
  'draft': 3
};

const sortByStatus = (statusA, statusB) => {
var a = itemOrder[statusA.get(0).status];
var b = itemOrder[statusB.get(0).status];
console.log(statusA.get(0).status, a, statusB.get(0).status, b)
  if ( a > b ) return 1;
  if (a < b ) return -1;
  return 0;
};

var result = Immutable.List(MyData)
  .groupBy(item => item.status)
  .sort( sortByStatus );
  
  console.log(result.toJS())
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>
StefanHayden
  • 3,569
  • 1
  • 31
  • 38
1

I think you were almost there. The important thing to notice is that .groupBy is returning a collection of lists, so when you call sort on that, you need a comparator that compares two different lists rather than two items. You can do this easily by just comparing the status of the first item in each list. After that, you want to sort each list individually by date, so you use .map to apply a change to each list in your list, then .sortBy on that list to sort by a specific key. Assuming you are using the built in Date type, just sorting by that field should do what you want.

var MyData = [
  {"id": 1, "status": "live", dateCreated: "12:00:00 01/02/2016"}, 
  {"id": 2, "status": "draft", dateCreated: "13:00:00 03/12/2015"}, 
  {"id": 3, "status": "ready", dateCreated: "16:00:00 04/09/2016"}, 
  {"id": 4, "status": "ready", dateCreated: "10:00:00 01/10/2016"}, 
  {"id": 5, "status": "live", dateCreated: "09:00:00 05/07/2015"}, 
  {"id": 6, "status": "draft", dateCreated: "08:00:00 11/03/2016"}, 
  {"id": 7, "status": "ready", dateCreated: "20:00:00 12/02/2016"}
]


Immutable.fromJs(MyData)
  // [{id: 1, ...}, ...]
  .groupBy(item => item.status) // group items into lists by status
  // [ 'live': [ { id: 1, ... }, { id:5, ... } ],
  //   'draft': [ { id: 2, ... }, { id: 6, ...} ],
  //   'ready': [ { id: 3, ... }, { id: 4, ... }, { id: 7, ... } ] ]
  .sort((listA, listB) => // order these groups by status
    itemOrder[listA.first().status] - itemOrder[listB.first().status])
  // [ 'live': [ { id: 1, ...}, ... ],
  //   'ready': [ { id: 3, ...}, ... ], 
  //   'draft': [ { id: 2, ...}, ... ] ]
  .map(list => list.sortBy(item => item.dateCreated)); // sort the elements in each group by date
  // [ 'live': [ { id: 5, ... }, { id: 1, ... } ],
  //   'ready': [ { id: 4, ... }, { id: 3, ... }, { id: 7, ... } ], 
  //   'draft': [ { id: 2, , ...}, { id: 6, ... } ] ]