Home > Mobile >  Better logic to check if a property is found in one of two collections and set the corresponding typ
Better logic to check if a property is found in one of two collections and set the corresponding typ

Time:08-04

I have a function with one parameter customerID. This can be the ID of a company or private person. Because the database structure is badly build I have to check if it is a Company or PrivatePerson in two separate calls.

My approach now is to define two variables customer and customer_type both set to null. I fetch for a company. If a company is found I assign the company to the customer variable and set customer_type to 'company'. If no company is found a fetch to the PrivatePersons collection is made and checked if a PrivatePerson is found. If so the fetched data gets assigned to the customer and customer_type is set to 'PrivatePerson'.

The code underneath is working to do all of this but it feels messy. The if/else with another if inside the else just doesn't feel right. I can be wrong but I think there is a better approach to this. Anyway up to give some advice on this?

const myFunction = async (customerID) => {
    let customer = null;
    let customer_type = null;

    const company = await Companies.findByID({ customerID });

    if(company) {
        customer = company;
        customer_type = 'Company'
    } else {
        const private_person = await PrivatePersons.findByID({ customerID });
        
        if(private_person) {
            customer = private_person;
            customer_type = 'PrivatePerson'
        }
    }

    if(!customer) {
        return
    }

    ...
}

CodePudding user response:

The tersest edit would look like this:

const getCustomer = async (customerID) => {
  let customer = await Companies.findByID({ customerID });
  return customer || await PrivatePersons.findByID({ customerID });
}

In the function above, or anyplace upstream, the customer type can be checked with:

async function someCaller() {
  const customer = await getCustomer(someId);
  const customer_type = customer.constructor.modelName; // will be either 'Companies' or 'PrivatePersons'
  // ...
}

edit

Generalizing, if the objective is to both find an object, and also convey where it was found, we need a little extra representation. A few ideas:

  1. If customers are ES6 objects, you can get the same effect as above with:
const customer = getCustomer(someId);
const customer_type = customer.constructor.name
  1. More generally, for generic objects, you could annotate the found object:
const getCustomer = async (customerID) => {
  // say we have arrays called companies and privatePersons
  let customer = companies.find(c => c.id === customerId);
  if (customer) customer.type = 'Companies';
  else {
    customer = privatePersons.find(p => p.id === customerId);
    customer?.type = 'PrivatePersons';
  }
  return customer;
}

1a. If the membership in one array or the other is pretty stable -- which it seems like it might be for your app -- then you can annotate the objects in advance...

companies = companies.map(c => ({ ...c, type: 'Companies' }));
privatePersons = privatePersons.map(p => ({ ...p, type: 'PrivatePersons' }));

Doing so simplifies getCustomer to:

const getCustomer = async (customerID) => {
  return companies.find(c => c.id === customerId) ||
    privatePersons.find(p => p.id === customerId);
}
  1. Another idea is to augment the found object. Have the getCustomer function return an object/type pair, like this:
const getCustomer = async (customerID) => {
  let type;  
  let customer = companies.find(c => c.id === customerId);
  if (customer) type = 'Companies';
  else {
    customer = privatePersons.find(p => p.id === customerId);
    type = 'PrivatePersons';
  }
  return { customer, type }
}

The caller instead of receiving the plain customer, would change like this...

let { customer, customer_type } = getCustomer(customerID);
  • Related