Home > Back-end >  Searching for category with subcategories in javascript array of objects
Searching for category with subcategories in javascript array of objects

Time:02-03

I'm building a search functionality where I need to search for a specific value to be find by part of its text. So I've got an example object:

const data = [
  {
    org_name: "A PFS COUNTRY TESTS",
    clients: [
      {
        name: "Abu Dhabi",
        type: "Yacht",
        currency: "EUR",
        notifications: {
          for_action: 0,
          for_attention: 0
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0
        }
      },
      {
        name: "Australia",
        type: "Yacht",
        currency: "AUD",
        notifications: {
          for_action: 0,
          for_attention: 0
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0
        }
      },
      {
        name: "Bermuda",
        type: "Yacht",
        currency: "EUR",
        notifications: {
          for_action: 0,
          for_attention: 0
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0
        }
      }
    ]
  },
  {
    org_name: "Music Tours",
    clients: [
      {
        name: "Music Demo",
        type: "Office",
        currency: "GBP",
        notifications: {
          for_action: 0,
          for_attention: 0
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0
        }
      },
      {
        name: "Summer Tour",
        type: "Office",
        currency: "GBP",
        notifications: {
          for_action: 0,
          for_attention: 0
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0
        }
      },
      {
        name: "Winter Tour",
        type: "Yacht",
        currency: "USD",
        notifications: {
          for_action: 0,
          for_attention: 0
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0
        }
      }
    ]
  },
  {
    org_name: "Dariusz Sandbox 1",
    clients: [
      {
        name: "Dariusz Test Client 1",
        type: "Yacht",
        currency: "EUR",
        notifications: {
          for_action: 0,
          for_attention: 0
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0
        }
      },
      {
        name: "Dariusz Test Client 2",
        type: "House",
        currency: "GBP",
        notifications: {
          for_action: 0,
          for_attention: 0
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0
        }
      },
      {
        name: "Dariusz Test Client 3",
        type: "Aircraft",
        currency: "USD",
        notifications: {
          for_action: 0,
          for_attention: 0
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0
        }
      }
    ]
  },
  {
    org_name: "Dariusz Sandbox 2",
    clients: [
      {
        name: "Dariusz Test Client 1",
        type: "Yacht",
        currency: "EUR",
        notifications: {
          for_action: 0,
          for_attention: 0
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0
        }
      }
    ]
  }
];

So if I'm looking for a "Dar" I should receive array with only org_name objects that have clients that include the "Dar" in their name value.

My solution is so far:

const newData = data.map((el) => {
  const filtered = el.clients.filter((client) => {
    if (client.name.includes("Dar")) {
      return client;
    }
  });
  if (filtered.length > 0) {
    return { org_name: el.org_name, clients: filtered };
  }
  
});

console.log("newData is", newData);

But what I've got is [undefined, undefined, Object, Object] instead of [Object, Object]

CodePudding user response:

The issue is your map() call. It will return an Object (your org) if it has at least one client that passes the filter(), but implicity returns undefined if filtered.length is not greater than zero.

In JS every function has a return -- either declared with return, or implicit. The default implicit value is undefined which is where those array entries are coming from. You could switch map() to filter() and it should work (since it will omit the falsy undefined values from the array).

const newData = data.filter((el) => { # NOTE: the change to .filter()
  const filtered = el.clients.filter((client) => {
    if (client.name.includes("Dar")) {
      return client;
    }
  });
  if (filtered.length > 0) {
    return { org_name: el.org_name, clients: filtered };
  }
  
});

console.log("newData is", newData);

CodePudding user response:

Your map function is always returning - but if it doesn't return anything, it will return undefined. You can use filter, as in @STW's answer, or you can use reduce to only get the ones you want.

const data = [
  {
    org_name: 'A PFS COUNTRY TESTS',
    clients: [
      {
        name: 'Abu Dhabi',
        type: 'Yacht',
        currency: 'EUR',
        notifications: {
          for_action: 0,
          for_attention: 0,
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0,
        },
      },
      {
        name: 'Australia',
        type: 'Yacht',
        currency: 'AUD',
        notifications: {
          for_action: 0,
          for_attention: 0,
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0,
        },
      },
      {
        name: 'Bermuda',
        type: 'Yacht',
        currency: 'EUR',
        notifications: {
          for_action: 0,
          for_attention: 0,
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0,
        },
      },
    ],
  },
  {
    org_name: 'Music Tours',
    clients: [
      {
        name: 'Music Demo',
        type: 'Office',
        currency: 'GBP',
        notifications: {
          for_action: 0,
          for_attention: 0,
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0,
        },
      },
      {
        name: 'Summer Tour',
        type: 'Office',
        currency: 'GBP',
        notifications: {
          for_action: 0,
          for_attention: 0,
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0,
        },
      },
      {
        name: 'Winter Tour',
        type: 'Yacht',
        currency: 'USD',
        notifications: {
          for_action: 0,
          for_attention: 0,
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0,
        },
      },
    ],
  },
  {
    org_name: 'Dariusz Sandbox 1',
    clients: [
      {
        name: 'Dariusz Test Client 1',
        type: 'Yacht',
        currency: 'EUR',
        notifications: {
          for_action: 0,
          for_attention: 0,
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0,
        },
      },
      {
        name: 'Dariusz Test Client 2',
        type: 'House',
        currency: 'GBP',
        notifications: {
          for_action: 0,
          for_attention: 0,
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0,
        },
      },
      {
        name: 'Dariusz Test Client 3',
        type: 'Aircraft',
        currency: 'USD',
        notifications: {
          for_action: 0,
          for_attention: 0,
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0,
        },
      },
    ],
  },
  {
    org_name: 'Dariusz Sandbox 2',
    clients: [
      {
        name: 'Dariusz Test Client 1',
        type: 'Yacht',
        currency: 'EUR',
        notifications: {
          for_action: 0,
          for_attention: 0,
        },
        unpaid_invoices: {
          total: 0,
          ok_to_pay: 0,
          reviewed: 0,
        },
      },
    ],
  },
];

const newData = data.reduce((acc, el) => {
  const filtered = el.clients.filter((client) => {
    if (client.name.includes('Dar')) {
      return client;
    }
  });

  if (filtered.length > 0) {
    acc.push({ org_name: el.org_name, clients: filtered });
  }
  return acc;
}, []);

console.log(newData);

  •  Tags:  
  • Related