0

I have an object so defined:

{
        _id: "5d406a171ed43384972f04b5",
        index: 0,
        age: 28,
        eyeColor: "brown",
        name: {
          first: "Myra",
          last: "Navarro"
        },
        company: "SUSTENZA",
        email: "myra.navarro@sustenza.net"
      }

I would need to be able to do the search on all keys, even in compound keys like name.

For example I have a search string name.first and the like, it could be even deeper and compound objects.

I managed to do this, but on name.first for example I am failing to get it to work.

Can you give me a hand?

let datatable = [
  {
    _id: "5d406a171ed43384972f04b5",
    index: 0,
    age: 28,
    eyeColor: "brown",
    name: {
      first: "Myra",
      last: "Navarro"
    },
    company: "SUSTENZA",
    email: "myra.navarro@sustenza.net"
  },
  {
    _id: "5d406a170db0f4b04d9a9acf",
    index: 1,
    age: 23,
    eyeColor: "blue",
    name: {
      first: "Harriett",
      last: "Tanner"
    },
    company: "VALPREAL",
    email: "harriett.tanner@valpreal.com"
  },
  {
    _id: "5d406a17e95da8ff80a759c5",
    index: 2,
    age: 39,
    eyeColor: "blue",
    name: {
      first: "Vega",
      last: "Hanson"
    },
    company: "BEDLAM",
    email: "vega.hanson@bedlam.tv"
  },
  {
    _id: "5d406a175505da190e6875ec",
    index: 3,
    age: 31,
    eyeColor: "blue",
    name: {
      first: "Rosemary",
      last: "Fields"
    },
    company: "QUAILCOM",
    email: "rosemary.fields@quailcom.me"
  },
  {
    _id: "5d406a17ea96044c027f4e50",
    index: 4,
    age: 27,
    eyeColor: "brown",
    name: {
      first: "Dale",
      last: "Wilkinson"
    },
    company: "QIAO",
    email: "dale.wilkinson@qiao.org"
  },
  {
    _id: "5d406a17c5fff1ff6653a555",
    index: 5,
    age: 25,
    eyeColor: "blue",
    name: {
      first: "Beatrice",
      last: "Contreras"
    },
    company: "ZENOLUX",
    email: "beatrice.contreras@zenolux.us"
  },
  {
    _id: "5d406a17a199efcba25e1f26",
    index: 6,
    age: 34,
    eyeColor: "blue",
    name: {
      first: "Hancock",
      last: "Wynn"
    },
    company: "PLASMOS",
    email: "hancock.wynn@plasmos.co.uk"
  },
  {
    _id: "5d406a17019a2a4544a4f134",
    index: 7,
    age: 40,
    eyeColor: "blue",
    name: {
      first: "Brown",
      last: "Stanton"
    },
    company: "SNACKTION",
    email: "brown.stanton@snacktion.name"
  },
  {
    _id: "5d406a17e516dd71af8210d4",
    index: 8,
    age: 39,
    eyeColor: "blue",
    name: {
      first: "Barnes",
      last: "Dunn"
    },
    company: "PORTALINE",
    email: "barnes.dunn@portaline.ca"
  },
  {
    _id: "5d406a17516936a025b73c33",
    index: 9,
    age: 34,
    eyeColor: "green",
    name: {
      first: "Blanche",
      last: "Cherry"
    },
    company: "ISOSWITCH",
    email: "blanche.cherry@isoswitch.io"
  },
  {
    _id: "5d406a17527a4d2c6a7897dd",
    index: 10,
    age: 33,
    eyeColor: "blue",
    name: {
      first: "Gilliam",
      last: "Farley"
    },
    company: "AMTAS",
    email: "gilliam.farley@amtas.biz"
  },
  {
    _id: "5d406a175ff11478c416c30b",
    index: 11,
    age: 26,
    eyeColor: "brown",
    name: {
      first: "Laura",
      last: "Short"
    },
    company: "FISHLAND",
    email: "laura.short@fishland.info"
  },
  {
    _id: "5d406a1738181b471847339a",
    index: 12,
    age: 20,
    eyeColor: "brown",
    name: {
      first: "Moreno",
      last: "Barber"
    },
    company: "KEENGEN",
    email: "moreno.barber@keengen.net"
  },
  {
    _id: "5d406a17a6bcae6fe3ad1735",
    index: 13,
    age: 30,
    eyeColor: "brown",
    name: {
      first: "Fischer",
      last: "French"
    },
    company: "INCUBUS",
    email: "fischer.french@incubus.com"
  },
  {
    _id: "5d406a17600ca53e8f63f263",
    index: 14,
    age: 30,
    eyeColor: "brown",
    name: {
      first: "Donaldson",
      last: "Carr"
    },
    company: "SUNCLIPSE",
    email: "donaldson.carr@sunclipse.tv"
  },
  {
    _id: "5d406a17530655789a27174f",
    index: 15,
    age: 35,
    eyeColor: "green",
    name: {
      first: "Sophia",
      last: "Payne"
    },
    company: "PRISMATIC",
    email: "sophia.payne@prismatic.me"
  },
  {
    _id: "5d406a175dbc687b4c7669d8",
    index: 16,
    age: 34,
    eyeColor: "green",
    name: {
      first: "Simone",
      last: "Pollard"
    },
    company: "DIGIGEN",
    email: "simone.pollard@digigen.org"
  },
  {
    _id: "5d406a179f35ed326a6a5567",
    index: 17,
    age: 28,
    eyeColor: "green",
    name: {
      first: "Yvette",
      last: "Daugherty"
    },
    company: "CHILLIUM",
    email: "yvette.daugherty@chillium.us"
  }
];

const sortAsc = true;
const sortField = "name.first";//index,eyeColor

var result = datatable.sort((a, b) => {
  let [x, z] = sortAsc ? [a, b] : [b, a];
  //console.log(x[sortField], z[sortField], x[sortField] > z[sortField] ? 1 : -1);
  return x[sortField] > z[sortField] ? 1 : -1;
});

console.log(result);

Edit:

It seems to work like this, but I would like to write it in a more compact form and possibly reduce the computation time.

Do you think it is possible?

var result = datatable.sort((a, b) => {
  let [x, z] = sortAsc ? [a, b] : [b, a];
  const arraySplit = sortField.split('.');
  var vX = arraySplit.reduce((a, b) => a[b], x);
  var vZ = arraySplit.reduce((a, b) => a[b], z);
  return vX > vZ ? 1 : -1;
});
Paul
  • 3,644
  • 9
  • 47
  • 113
  • You can use eval, it is not recommended, but I think in this case it is safe, var result = datatable.sort((a, b, i) => eval(`a.${sortField}`) - eval(`b.${sortField}`)); – lissettdm Dec 02 '20 at 13:57

3 Answers3

1

First issue is that javascript doesn't automatically access children using dots.

If you want to implement that, here are some solutions: Access object child properties using a dot notation string

Next, once you have the value you want to compare with.

You need to use a special string compare function if the value is a string (use typeof to check). Or use valA - valB so that you get 1, 0, and -1 as the return values to sort with.

John
  • 5,942
  • 3
  • 42
  • 79
  • I found a possible solution, but I would like to improve it as I say in the edit, can you give me a hand? – Paul Dec 02 '20 at 11:39
  • @Paul You're still not comparing the values correctly. Rather than creating and flipping objects. You can multiply the resulting value by -1 if you want to reverse its order. – John Dec 02 '20 at 11:42
1

I hope this is what you need. The child function makes what you need. You have the explanation in the comments.

let datatable = [
  {
    _id: "5d406a171ed43384972f04b5",
    index: 0,
    age: 28,
    eyeColor: "brown",
    name: {
      first: "Myra",
      last: "Navarro"
    },
    company: "SUSTENZA",
    email: "myra.navarro@sustenza.net"
  },
  {
    _id: "5d406a170db0f4b04d9a9acf",
    index: 1,
    age: 23,
    eyeColor: "blue",
    name: {
      first: "Harriett",
      last: "Tanner"
    },
    company: "VALPREAL",
    email: "harriett.tanner@valpreal.com"
  },
  {
    _id: "5d406a17e95da8ff80a759c5",
    index: 2,
    age: 39,
    eyeColor: "blue",
    name: {
      first: "Vega",
      last: "Hanson"
    },
    company: "BEDLAM",
    email: "vega.hanson@bedlam.tv"
  },
  {
    _id: "5d406a175505da190e6875ec",
    index: 3,
    age: 31,
    eyeColor: "blue",
    name: {
      first: "Rosemary",
      last: "Fields"
    },
    company: "QUAILCOM",
    email: "rosemary.fields@quailcom.me"
  },
  {
    _id: "5d406a17ea96044c027f4e50",
    index: 4,
    age: 27,
    eyeColor: "brown",
    name: {
      first: "Dale",
      last: "Wilkinson"
    },
    company: "QIAO",
    email: "dale.wilkinson@qiao.org"
  },
  {
    _id: "5d406a17c5fff1ff6653a555",
    index: 5,
    age: 25,
    eyeColor: "blue",
    name: {
      first: "Beatrice",
      last: "Contreras"
    },
    company: "ZENOLUX",
    email: "beatrice.contreras@zenolux.us"
  },
  {
    _id: "5d406a17a199efcba25e1f26",
    index: 6,
    age: 34,
    eyeColor: "blue",
    name: {
      first: "Hancock",
      last: "Wynn"
    },
    company: "PLASMOS",
    email: "hancock.wynn@plasmos.co.uk"
  },
  {
    _id: "5d406a17019a2a4544a4f134",
    index: 7,
    age: 40,
    eyeColor: "blue",
    name: {
      first: "Brown",
      last: "Stanton"
    },
    company: "SNACKTION",
    email: "brown.stanton@snacktion.name"
  },
  {
    _id: "5d406a17e516dd71af8210d4",
    index: 8,
    age: 39,
    eyeColor: "blue",
    name: {
      first: "Barnes",
      last: "Dunn"
    },
    company: "PORTALINE",
    email: "barnes.dunn@portaline.ca"
  },
  {
    _id: "5d406a17516936a025b73c33",
    index: 9,
    age: 34,
    eyeColor: "green",
    name: {
      first: "Blanche",
      last: "Cherry"
    },
    company: "ISOSWITCH",
    email: "blanche.cherry@isoswitch.io"
  },
  {
    _id: "5d406a17527a4d2c6a7897dd",
    index: 10,
    age: 33,
    eyeColor: "blue",
    name: {
      first: "Gilliam",
      last: "Farley"
    },
    company: "AMTAS",
    email: "gilliam.farley@amtas.biz"
  },
  {
    _id: "5d406a175ff11478c416c30b",
    index: 11,
    age: 26,
    eyeColor: "brown",
    name: {
      first: "Laura",
      last: "Short"
    },
    company: "FISHLAND",
    email: "laura.short@fishland.info"
  },
  {
    _id: "5d406a1738181b471847339a",
    index: 12,
    age: 20,
    eyeColor: "brown",
    name: {
      first: "Moreno",
      last: "Barber"
    },
    company: "KEENGEN",
    email: "moreno.barber@keengen.net"
  },
  {
    _id: "5d406a17a6bcae6fe3ad1735",
    index: 13,
    age: 30,
    eyeColor: "brown",
    name: {
      first: "Fischer",
      last: "French"
    },
    company: "INCUBUS",
    email: "fischer.french@incubus.com"
  },
  {
    _id: "5d406a17600ca53e8f63f263",
    index: 14,
    age: 30,
    eyeColor: "brown",
    name: {
      first: "Donaldson",
      last: "Carr"
    },
    company: "SUNCLIPSE",
    email: "donaldson.carr@sunclipse.tv"
  },
  {
    _id: "5d406a17530655789a27174f",
    index: 15,
    age: 35,
    eyeColor: "green",
    name: {
      first: "Sophia",
      last: "Payne"
    },
    company: "PRISMATIC",
    email: "sophia.payne@prismatic.me"
  },
  {
    _id: "5d406a175dbc687b4c7669d8",
    index: 16,
    age: 34,
    eyeColor: "green",
    name: {
      first: "Simone",
      last: "Pollard"
    },
    company: "DIGIGEN",
    email: "simone.pollard@digigen.org"
  },
  {
    _id: "5d406a179f35ed326a6a5567",
    index: 17,
    age: 28,
    eyeColor: "green",
    name: {
      first: "Yvette",
      last: "Daugherty"
    },
    company: "CHILLIUM",
    email: "yvette.daugherty@chillium.us"
  }
];

const sortAsc = true;
const sortField = "name.first";//index,eyeColor

var result = datatable.sort((a, b) => {
  let [x, z] = sortAsc ? [a, b] : [b, a];
  //console.log(x[sortField], z[sortField], x[sortField] > z[sortField] ? 1 : -1);
  //return x[sortField] > z[sortField] ? 1 : -1;
  return child(x, sortField) > child(z, sortField) ? 1: -1;
});

console.log(result);

function child(obj, str){
  //take dot-separated chain of properties' names and split them into an array
  const props = str.split('.');
  let child = obj;
  //looop through all properties' names and get the access to the following [Object] children sequentially
  props.forEach((prop)=> child = child[prop]);
  return child;
}
Paweł
  • 4,238
  • 4
  • 21
  • 40
1

Option 1:

const objRoute = sortField.split(".");
const getValue = obj => objRoute.reduce((v, c) => v[c], obj);
const result = datatable.sort((a, b) =>
  sortAsc
    ? getValue(a).localeCompare() - getValue(b).localeCompare()
    : getValue(b).localeCompare() - getValue(a).localeCompare()
);

Option 2:

Use eval, eval() evaluates the expression. It is recommended to use this function with caution:

const result = datatable.sort((a, b, i) => eval(`a.${sortField}`) - eval(`b.${sortField}`));
lissettdm
  • 12,267
  • 1
  • 18
  • 39
  • The code doesn't seem to work correctly, getValue returns undefined and then how do I go about sorting by asc or desc using the variable I use? – Paul Dec 03 '20 at 16:05
  • You are right! I edited my answer, I added localCompare. – lissettdm Dec 03 '20 at 16:28