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 request
object.
4 Answers 4
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'
}))
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);
-
Hm, nice, it seemds that JSfiddle is sorting the output console.log, jesus, spend hours looking the jsfiddle console, and not the Chrome console.pmiranda– pmiranda2020年11月13日 16:12:11 +00:00Commented 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.Olian04– Olian042020年11月13日 16:13:31 +00:00Commented Nov 13, 2020 at 16:13
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.
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')
-
1This would fail if
undefined
is a valid value for a required field.Olian04– Olian042020年11月13日 16:14:56 +00:00Commented Nov 13, 2020 at 16:14 -
Yes, some data could be:
data = { id: 1, token: null, status: false, name: undefined, code: '' }
pmiranda– pmiranda2020年11月13日 16:18:30 +00:00Commented 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 checkepascarello– epascarello2020年11月13日 16:20:14 +00:00Commented Nov 13, 2020 at 16:20
I need to order the request by fieldsOrder
, why?