0

I have this function that sort some input object based on an array called keys;

const keys = ["token", "agentID", "agentSequence", "allOptions"]

function sortRequest(request) {
  return keys.reduce((sortedRequest, key) => {
    if (key in request) {
      sortedRequest[key] = request[key]
    }
    return sortedRequest
  }, {})
}


console.log(sortRequest({
  allOptions: false,
  agentSequence: 6,
  agentID: 123,
  token: 'test',
  notVisible: true
}));

The only problem is if some value of the input is not present on the array it will be lost on the returned object. I'm trying to fix this issue, but couldn't get it. The idea is to get each property of the object.

Barmar
  • 596,455
  • 48
  • 393
  • 495
pmiranda
  • 4,757
  • 7
  • 35
  • 74
  • fyi object property is practically guaranteed but could change. you shouldn't absolutely rely on it. – Daniel A. White Nov 13 '20 at 20:01
  • What you're doing there is filtering the object by the keys available. It's because you're only looping through the keys you've specified. Are you trying to get an object who's keys are sorted in alphabetical order? If so you could set the const keys to Object.keys(request).sort() and then run your reduce. But in general a sorted object isn't really worthwhile and you shouldn't be relying on any sorting of keys in an object. – WakeskaterX Nov 13 '20 at 20:01
  • I don't understand exactly what you trying to do. When you say sort input object what do u mean. – urchmaney Nov 13 '20 at 20:02
  • No, no alphabetically sorting, just to follow the order from the `keys` arrays. In that array `token` is first, and so on. I need to send this object sorted with the way that array is sorted. I know that objects sorting is a very large issue, with many scopes where may it fails, but this object will be sent to an external SOAP api made in 1999 with a lot of history behind... I can't control what receives that API (it has many if inside a for, etc...). – pmiranda Nov 13 '20 at 20:05
  • Why don't you do the ordering in the function that sends to the SOAP API, rather than in the object itself? – Barmar Nov 13 '20 at 20:10
  • How are you converting the object into the SOAP parameters? Because the operation you're using might not preserve the property order. – Barmar Nov 13 '20 at 20:11
  • Because the object is read from the request body directly, I can't control what order use the client to send the request parameters, so I'm sorting them after receiving them, then I send them to the SOAP API, I get a response, then I return that response to the client. – pmiranda Nov 13 '20 at 20:12

3 Answers3

1

Objects cannot be reordered. Objects are by definition unordered. Some javascript engine (most of them these days) do have some sort order but do not depend on it since the standard does not specify object key sorting behavior.

If you need a specific key order you need a Map. Or if you want to do it the traditional way you need an array:

[
  ["token", "agentID", "agentSequence", "allOptions"]
  { key: "token", value: 'test' },
  { key: "agentID", value: 123 },
  { key: "agentSequence", value: 6 },
  { key: "allOptions", value: false },
  { key: "notVisible", value: true}
]

This of course does not answer your question. Instead do not even attempt to do what you are doing.

slebetman
  • 93,070
  • 18
  • 116
  • 145
  • 1
    ES6 says that non-numeric keys preserve insertion order. See https://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order – Barmar Nov 13 '20 at 20:04
  • That's a misreading of the spec. ES6 simply says that the keys maintain the order returned by `Object.keys()` and then don't specify what that order is. Originally I also thought that's what the spec said until one of my answers was disputed and I had to read the wording of the spec more carefully – slebetman Nov 13 '20 at 20:06
1

After getting the properties that are in keys, do a second pass over the original object and add in the properties that are missing.

const keys = ["token", "agentID", "agentSequence", "allOptions"]

function sortRequest(request) {
  const result = keys.reduce((sortedRequest, key) => {
    if (key in request) {
      sortedRequest[key] = request[key]
    }
    return sortedRequest
  }, {});
  return Object.entries(request).reduce((sortedRequest, [key, value]) => {
    if (!(key in keys)) {
      sortedRequest[key] = value;
    }
    return sortedRequest;
  }, result)
}


console.log(sortRequest({
  allOptions: false,
  agentSequence: 6,
  agentID: 123,
  token: 'test',
  notVisible: true
}));
Barmar
  • 596,455
  • 48
  • 393
  • 495
1

Simple forEach and spread will do the trick.

const input = {
  allOptions: false,
  agentSequence: 6,
  agentID: 123,
  token: 'test',
  notVisible: true
};

const keys = ["token", "agentID", "agentSequence", "allOptions"];

function orderInput(input, keys) {
  let ordered = {};
  keys.forEach(function (key) {
    if (key in input) {
      ordered[key] = input[key];
    }
  });

  return {...ordered, ...input};
}

console.log(orderInput(input, keys));
SirPilan
  • 3,863
  • 2
  • 9
  • 23