0

I am a bit stuck. First off, I know there are similar questions, and I have tried various different options, but I am simply missing something. I have not had to do this type of method before, so I would appreciate your help and kindness.

I know I should use (I think) Object.keys and .map, and a function that looks something like this:

function comp(a, b) {
    return new Date(a.result.date).getTime() - new Date(b.result.date).getTime();
}

but I am struggling to get it to work.

I have tried:

var uptime = $scope.frequencyData.production_deploys;

var myObjects = Object.keys(uptime).map(function (itm) {
    return uptime[itm];
});

var arr = [];

for (key in uptime) {
    uptime[key].time = key;
    arr.push(uptime[key]);
}

arr.sort(function (a, b) {
    return new Date(a.time) - new Date(b.time);
});

But this created an array with no dates.

I have tried:

uptime = Object.keys($scope.frequencyData.production_deploys);

But this created an array with only dates

So here is my Question:

STEP 1: How can I sort an object of objects ({{}, {}, {}} (JSON) according to the date parameter, and then

STEP 2: Find the last date where the object has a parameter of success

STEP 3: And then assign this to a var?

This is my JSON data (object of objects):

{
  "production_deploys": {
    "2017-07-08": {
      "failures": 2,
      "success": 1
    },
    "2017-07-09": {
      "failures": 2,
      "success": 1
    },
    "2017-07-10": {
      "failures": 2,
      "success": 3
    },
    "2017-07-11": {
      "failures": 2,
      "success": 10
    },
    "2017-07-12": {
      "failures": 2,
      "success": 2
    },
    "2017-07-13": {
      "failures": 2,
      "success": 2
    },
    "2017-07-14": {
      "failures": 2,
      "success": 1
    },
    "2017-07-15": {
      "failures": 2,
      "success": 1
    },
    "2017-07-16": {
      "failures": 2,
      "success": 1
    },
    "2017-07-17": {
      "failures": 2,
      "success": 3
    },
    "2017-07-18": {
      "failures": 2,
      "success": 10
    }
  },
  "pull_requests": {

  },
  "test_deploys": {

  },
  "uptime": {

  }
}

The data I would like to sort after retrieving the data, would be $scope.frequencyData.production_deploys.

Desired output would be: $scope.lastScuccessfulProductionDeploy = the correct object.date;

Some refs I have looked at:

sort JSON by date

Sorting an array of JavaScript objects

onmyway
  • 1,435
  • 3
  • 29
  • 53
  • Possible duplicate of [Does JavaScript Guarantee Object Property Order?](https://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order) – str Jul 19 '17 at 11:34
  • I am well aware of similar questions, but I am struggling to make it work. Please be patient. :) – onmyway Jul 19 '17 at 11:36
  • 1
    Object properties aren't ordered. What you can do is push each key-value pair in an array so you can sort the items. – dork Jul 19 '17 at 11:37
  • @onmyway Well, apparently you are not aware of the *answers* then. Because they tell you that you cannot order the content of plain JavaScript objects. – str Jul 19 '17 at 11:39
  • @onmyway - To avoid being marked as a duplicate, please be specific about how you failed to apply the lessons learned from other similar questions. – Fred Gandt Jul 19 '17 at 11:39
  • 1
    @FredGandt i will update my question. Thank you. – onmyway Jul 19 '17 at 11:40
  • @onmyway, why do you need sortign if you use only one value? – Nina Scholz Jul 19 '17 at 14:12

4 Answers4

2

Beside the given answers with bad big O (filtering, mapping, sorting), you could use a single loop approach with Array#reduce.

var data = { production_deploys: { "2017-07-08": { failures: 2, success: 1 }, "2017-07-09": { failures: 2, success: 1 }, "2017-07-10": { failures: 2, success: 3 }, "2017-07-11": { failures: 2, success: 10 }, "2017-07-12": { failures: 2, success: 2 }, "2017-07-13": { failures: 2, success: 2 }, "2017-07-14": { failures: 2, success: 1 }, "2017-07-15": { failures: 2, success: 1 }, "2017-07-16": { failures: 2, success: 1 }, "2017-07-17": { failures: 2, success: 3 }, "2017-07-18": { failures: 2, success: 10 } }, pull_requests: {}, test_deploys: {}, uptime: {} },
    result = Object.keys(data.production_deploys).reduce(function (r, a) {
        return !data.production_deploys[a].success || r > a ? r : a;
    }, '');

console.log(result);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

To sort your object of objects, you should create a outside list of keys. This because Javascript does not guarantee that the keys of an object are sortable.

var sortedKeys = Object.keys(myObject).sort(mySortFunction);

When you want to access this object you use a function that point to this list.

If your object changes, you should update the list accordingly.

The point 2 is trivial, you don't need any kind of order, just browse the object kesy and find the last date with the property value you're looking for.

var lastDateObject = null;
var lastDate = null;
for (let keyName in myObject) {
    if (elementHasSuccess(myObject[keyName]) && compareDates(lastDate, keyName)) {
          lastDateObject = Object.assign({}, myObject[keyName]);
      }
}

Or something like this, that solves the third point too.

UPDATE

The function that are used to order a list should have the following signature:

function compare(a, b) { if (a is less than b by some ordering criterion) { return -1; } if (a is greater than b by the ordering criterion) { return 1; } // a must be equal to b return 0; }

Get from Mozilla documentation: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

As in your case you're comparing Dates you could first convert string in date:

var dateA = new Date(a);
var dateB = new Date(b);

Then return the difference of the timestamps (milliseconds):

return dateA.getTime()-dateB.getTime();
Mario Santini
  • 2,905
  • 2
  • 20
  • 27
  • Thank you for your response Mario. How would the `mySortFunction` look like? This is part where I struggle. I am not sure how to correctly create a list of keys, and then to use and iterate through it. – onmyway Jul 19 '17 at 11:53
  • Thank you for the update and answer! i am still trying to figure it out :) – onmyway Jul 19 '17 at 12:11
1

Object properties aren't ordered. What you can do is filter the production_deploys items that have success properties (and greater than 0). Next is to change the keys to Date objects. Finally, you sort the array, latest first, and get the first item.

var sorted = Object.keys(data.production_deploys)
  .filter(function (deployDate) {
    return data.production_deploys[deployDate].success &&
           data.production_deploys[deployDate].success > 0;
  })
  .map(function (deployDate) {
    return new Date(deployDate);
  })
  .sort(function (a, b) {
    return b.getTime() - a.getTime();
  });

var latestSuccessfulDate = sorted[0];

var data = {
  "production_deploys": {
    "2017-07-08": {
      "failures": 2,
      "success": 1
    },
    "2017-07-09": {
      "failures": 2,
      "success": 1
    },
    "2017-07-10": {
      "failures": 2,
      "success": 3
    },
    "2017-07-11": {
      "failures": 2,
      "success": 10
    },
    "2017-07-12": {
      "failures": 2,
      "success": 2
    },
    "2017-07-13": {
      "failures": 2,
      "success": 2
    },
    "2017-07-14": {
      "failures": 2,
      "success": 1
    },
    "2017-07-15": {
      "failures": 2,
      "success": 1
    },
    "2017-07-16": {
      "failures": 2,
      "success": 1
    },
    "2017-07-17": {
      "failures": 2,
      "success": 3
    },
    "2017-07-18": {
      "failures": 2,
      "success": 10
    }
  },
  "pull_requests": {

  },
  "test_deploys": {

  },
  "uptime": {

  }
};

var sorted = Object.keys(data.production_deploys)
  .filter(function (deployDate) {
    return data.production_deploys[deployDate].success &&
           data.production_deploys[deployDate].success > 0;
  })
  .map(function (deployDate) {
    return new Date(deployDate);
  })
  .sort(function (a, b) {
    return b.getTime() - a.getTime();
  });

var latestSuccessfulDate = sorted[0];

console.log(latestSuccessfulDate);
dork
  • 4,396
  • 2
  • 28
  • 56
  • Thank you dork! You made my day. :) – onmyway Jul 19 '17 at 12:15
  • @onmyway no problem. But I think `Nina Scholz`'s answer is better (https://stackoverflow.com/a/45192973/769326). Just add a `new Date(r or a)` if you want the `Date` object. – dork Jul 20 '17 at 03:01
0

one more solution..

var tt1 = Object.keys(tt.production_deploys)
.map(function(ke) { if (tt.production_deploys[ke].success == "1") { tt.production_deploys[ke].date = ke; return tt.production_deploys[ke]  } })
.filter(function (itm) { return itm !== undefined; })
.reduce(function (a, b) { return a.date > b.date ? a.date : b.date; })

considered "success == 1" you can change if it needs other criteria. works fine with current date format, but might need slight changes to adapt other date formats.

Immanuel
  • 167
  • 1
  • 8