0

Goal: to create an object with an specific order defined by an object, but only when the fields exists on the input data.

What I have and done:

This object defines the order:

const fieldsOrder = {
 token: undefined,
 agentID: undefined,
 agentSequence: undefined,
 allOptions: undefined
}

This is the body request that I need to sort:

const request = {
 allOptions: false,
 agentSequence: 6,
 agentID: 123,
 token: 'test'
}

The sorted object is sortedObject

const sortedObject = Object.assign(fieldsOrder, request);
console.log(sortedObject);
{
 agentID: 123,
 agentSequence: 6,
 allOptions: false,
 token: 'test'
}

Not working.

I was trying what I found here: Changing the order of the Object keys....

Here are some tests:

// This object defines de order:
const fieldsOrder = {
 token: undefined,
 agentID: undefined,
 agentSequence: undefined,
 allOptions: undefined
}
// 1st case: all fields
// This is the body request that I need to sort:
const request = {
 allOptions: true,
 agentSequence: 6,
 agentID: 123,
 token: 'test',
}
// The sorted object is `sortedRequest`
const sortedRequest = Object.assign(fieldsOrder, request);
// WRONG order...
console.log(sortedRequest); 
/*
I expected this order:
{
 token: 'test'
 agentID: 123,
 agentSequence: 6,
 allOptions: false
}
*/
/*************************************/
// 2nd case: some fields
const requestShort = {
 allOptions: true,
 agentID: 123,
 token: 'test',
}
const sortedRequest2 = Object.assign(fieldsOrder, requestShort);
// WRONG order...
console.log(sortedRequest2); 
/*
I expected this order:
{
 token: 'test'
 agentID: 123,
 allOptions: false
}
*/

How could I fix it? I need to order the request by fieldsOrder but only using the fields on the requestobject.

asked Nov 13, 2020 at 15:57
12
  • 2
    I need to order the request by fieldsOrder, why? Commented Nov 13, 2020 at 15:58
  • I will send that object to an stupid API (SOAP, badly designed) that needs a certain order or it fails. Commented Nov 13, 2020 at 16:01
  • You could just create a different object with the keys in the correct order and just set their values to the values from the out of order object. It’s not a fancy solution but it will work. You can even put it in a function to reuse it. Commented Nov 13, 2020 at 16:04
  • The order of fields have only recently become deterministic, if you run code that depends on field order on an old machine or in an old browser, then it will fail randomly. Commented Nov 13, 2020 at 16:05
  • Keep in mind that objects are not a good option if you need an ordered collection of items. The ideal would be either an array or a Map, where the order is guaranteed. See more: stackoverflow.com/a/5525820/3496534 Commented Nov 13, 2020 at 16:05

4 Answers 4

2

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'
}))

Tibebes. M
7,6085 gold badges18 silver badges39 bronze badges
answered Nov 13, 2020 at 16:12
1

You could use Object#entries to get an array of key-value tuples, then sort that array based on the index of each key in the "targetOrder" object, then turn those key-value tuples back into an object using Object#fromEntries. However the order of fields have only recently become deterministic, if you run code that depends on field order on an old machine or in an old browser, then it will fail randomly.

const targetOrder = Object.keys({
 token: undefined,
 agentID: undefined,
 agentSequence: undefined,
 allOptions: undefined
});
const req = {
 allOptions: true,
 agentSequence: 6,
 agentID: 123,
 token: 'test',
}
const orderedReq = Object.fromEntries(
 Object.entries(req)
 .sort(([k1], [k2]) =>
 targetOrder.indexOf(k1) - targetOrder.indexOf(k2)
 ),
);
console.log(orderedReq);

answered Nov 13, 2020 at 16:08
2
  • Hm, nice, it seemds that JSfiddle is sorting the output console.log, jesus, spend hours looking the jsfiddle console, and not the Chrome console. Commented Nov 13, 2020 at 16:12
  • @pmiranda I was thinking that might have been the case, but since I'm not sure what system/environment you where on I couldn't be sure. Commented Nov 13, 2020 at 16:13
0

You can iterate trough the keys of the request object and assign every key that exist in fieldsOrder. After that just simply remove all unset fields.

const fieldsOrder = {
 token: undefined,
 agentID: undefined,
 agentSequence: undefined,
 allOptions: undefined
}
const request = {
 allOptions: false,
 agentSequence: 6,
 agentID: 123,
 token: 'test'
}
Object.keys(request)
 .filter(key => key in fieldsOrder)
 .forEach(key => fieldsOrder[key] = request[key])
Object.keys(fieldsOrder)
 .filter(key => fieldsOrder[key] === undefined)
 .forEach(key => delete fieldsOrder[key])

With this solution you do not need to modify your existing objects or creating any string array.

answered Nov 13, 2020 at 16:11
0

So have an array of keys and loop over it to make a new object.

var fields = ['foo', 'bar', 'baz'];
var data1 = {
 baz: 456,
 foo: 123
};
var data2 = {
 baz: 987,
 foo: 765,
 bar: undefined
};
// only returned if has value
function test1(data) {
 return fields.reduce((o, k) => {
 if (data[k] !== undefined) o[k] = data[k];
 return o;
 }, {});
}
// return everything
function test2(data) {
 return fields.reduce((o, k) => (o[k] = data[k], o), {});
}
// return if it has the key
function test3(data) {
 return fields.reduce((o, k) => {
 if (k in data) {
 o[k] = data2[k];
 }
 return o;
 }, {});
}
console.group('test1')
console.log(test1(data1));
console.log(test1(data2));
console.groupEnd('test1')
console.group('test2')
console.log(test2(data1));
console.log(test2(data2));
console.groupEnd('test2')
console.group('test3')
console.log(test3(data1));
console.log(test3(data2));
console.groupEnd('test3')

answered Nov 13, 2020 at 16:12
3
  • 1
    This would fail if undefined is a valid value for a required field. Commented Nov 13, 2020 at 16:14
  • Yes, some data could be: data = { id: 1, token: null, status: false, name: undefined, code: '' } Commented Nov 13, 2020 at 16:18
  • @Olian04 I made an assumption it was just items that are defined. Lack of data of what values could be means I HAVE TO GUESS. Hence why these details need to be given. So if it can be undefined, remove the check. I altered it to remove the undefined check Commented Nov 13, 2020 at 16:20

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.