Home > Back-end >  How should I create an object that stores ids with sub ids without using arrays?
How should I create an object that stores ids with sub ids without using arrays?

Time:08-15

I need to send data to the server that has multiple ids with sub ids in it. Currently I am using arrays but because I need to handle each id and sub ids on the dom (currently with vue) I use a lot of find() and findIndex() again and again. If there is a way to use ids directly I just could access or check them with order[id][subid].

Currently I am using this structure:

let data = {
    orders: [
        { order_id: 4, items: [{ item_id: 6 }, { item_id: 7 }, { item_id: 8 }] },
        { order_id: 1, items: [{ item_id: 1 }, { item_id: 2 }, { item_id: 3 }] },
    ];
}

Here when I for example want yo check if a orders item is checked I have to

function check(order_id, item_id) {
    let order_i = data.orders.findIndex((o) => o.order_id == order_id);

    if (order_i != -1) {
        let item_i = data.orders[order_i].items.findIndex((o) => o.item_id == item_id);
    }

    if (item_i != -1) {
        return true;
    } else {
        return false;
    }
}

or something like that. What I want to use it like

let data = {
    orders: {
        4: {6:'',7:'',8:''},
        1: {1:'',2:'',3:''}
    }
}

and then I would just use data.orders?.[order_id]?.[item_id]

I am not sure would that be a good approach. Doesn't look so. What structure could I use for this, without using arrays ?

CodePudding user response:

I think the data structure you want is the Map. It stores key-value pairs and can retrieve the value of a specific key in constant time (rather than searching the whole list). The set(key, value) and get(key) methods are for interacting with the Map object.

If all orders are stored in this structure, you should use the id as the index in an array, that would be the most efficient. You can use a Map for the orders if they are not sequential (not all ids are present), and another Map for items. If on average there are not many items in a given order, then using an Array for that should be fine.

Read more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

CodePudding user response:

Presented below is one possible way to achieve the desired objective.

Code Snippet

// methoed to transform data into desired format
const transformMyData = obj => ({
  orders: obj?.orders?.reduce(      // iterate using ".reduce()" for orders
    (acc, {order_id, items, ...rest1}) => (   // transform each array-elt into prop-value format
      acc[order_id] ??= {},
      acc[order_id] = {...rest1},
      acc[order_id].items = items.reduce(     // iterate items
        (ac2, {item_id, ...rest2}) => (  // transform into prop-value format
          ac2[item_id] ??= {},
          ac2[item_id] = {...rest2},
          ac2
        ),
        {}    // this may be replaced with new Map() to use map instead of object
      ),
      acc
    ),
    {}        // this may be replaced with new Map() to use map instead of object
  )
});

// NOTE: If using "new Map()", please use ".get()" and ".set()" to access & set-up/update.

const data = {
  orders: [{
    order_id: 4, otherOrderProps: 'otherOrderValues1',
    items: [{
      item_id: 6, otherItemProps: 'a6'
    }, {
      item_id: 7, otherItemProps: 'a7'
    }, {
      item_id: 8, otherItemProps: 'a8'
    }]
  }, {
    order_id: 1, otherOrderProps: 'otherOrderValues2',
    items: [{
      item_id: 1, otherItemProps: 'a1'
    }, {
      item_id: 2, otherItemProps: 'a2'
    }, {
      item_id: 3, otherItemProps: 'a3'
    }]
  }]
};

console.log('transformed data:\n', transformMyData(data));

console.log(
  '\n\ncheck for order: 1, item: 2\n',
  transformMyData(data)?.orders?.[1]?.items?.[2] ?? 'not-found'
);

console.log(
  '\n\ncheck for non-existent order: 3, item: 2\n',
  transformMyData(data)?.orders?.[3]?.items?.[2] ?? 'not-found'
);
.as-console-wrapper {
  max-height: 100% !important;
  top: 0
}

Explanation

Inline comments added to the snippet above.

  • Related