I have an object result that can be received like for example:
const firstRowVoucher = result[0]['Voucher ID'] || result[0]['voucher_id'] || result[0]['VOUCHER_ID'];
const firstRowInvoice = result[0]['Invoice'] || result[0]['INVOICE'] || result[0]['invoice'];
if (firstRowVoucher && firstRowInvoice){
//do some code
}
result.forEach((element) => {
const elementVoucher = element['Voucher ID'] || result[0]['voucher_id'] || element['VOUCHER_ID'];
const elementStatus = element['Invoice'] || result[0]['INVOICE'] || element['invoice'];
if(elementVoucher && elementStatus){
// do some other stuff
}
});
It works, but it seems a little messy because there are lot of other words and conditionals.
Is there a way to check in a list of names if the object has those names as attributes? In order to get a better maintenance and better readability.
Maybe using an object array or something like this:
const fields = {
unit: ['Unit' || 'unit' || 'UNIT'],
voucherID: ['Voucher ID' || 'voucher_id' || 'VOUCHER_ID'],
invoice: ['Invoice' || 'INVOICE' || 'invoice'],
status: ['status' || 'STATUS' || 'Status'],
invoiceGrossAmount: [
'Invoice Gross Amount' ||
'Invoice_Gross_Amount' ||
'invoice gross amount' ||
'invoice_gross_amount',
],
currency: ['Currency' || 'currency'],
SupplierID: [
'Supplier ID' || 'supplier_id' || 'Supplier_Id' || 'Supplier_ID',
],
PONumber: ['PO Number' || 'PO_Number' || 'po_number' || 'po number'],
status: ['status' || 'Status' || 'STATUS'],
};
I'm not sure how to proceed.
You can make a little helper function that checks the various versions for you so you only have that code in one place:
// pass any case example with optional space or underline
function getField(obj, example) {
// create canonical lowerCase version with single space delimiters
const exSpace = example.replace(/\s+|_+/g, " ").toLowerCase();
let props = Object.entries(obj);
for (let propName of props) {
// take candicate property name and convert it to canonical
// form of lowercase, space delimited, spaces and underscores collapsed
const propCanonical = propName.toLowerCase().replace(/\s+|_+/g, " ");
if (propCanonical === exSpace) {
return obj[propName];
}
}
return null;
}
And, then use it like this:
const firstRowVoucher = getField(result[0], 'Voucher ID');
const firstRowInvoice = getField(result[0], 'Invoice');
FYI, the very fact that you don't know what the form of the field name is seems like some bad code somewhere before this that should be cleaned up. If you really have no control over the quality of the input, then maybe you should just sanitize the whole input before you every handle it so once you get result, it's only using standardized field names.
I would recommend transforming your result objects into one specific format. One way to achieve this would be setting all your keys to snake_case
const snakeCaseResults = result.map((obj) =>
Object.entries(obj).reduce(
(res, [key, value]) => ({ ...res, [key.toLowerCase().replaceAll(' ', '_')]: value }),
{}
)
)
this way you can always access your result using snake_case
E.g.
const firstRowVoucher = snakeCaseResults[0]['voucher_id'];
const firstRowInvoice = snakeCaseResults[0]['invoice'];