5

There is an array of objects (489 objects). An object has a key which has another object (child object). Number of child object is indefinite.

I've created a fiddle as well. Please find below search function:

function getObjects(obj, key, val) {
    var objects = [];
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == 'object') {
            parent = obj;
            objects = objects.concat(getObjects(obj[i], key, val));    
        } else {
            if(obj[i].toString().toLowerCase().indexOf(val.toString().toLowerCase()) > -1) {
                objects.push(obj);
            }
        } 
    }
    return objects;
} 

Here I want to search for a search string in an array of object including nested object (asset_info) as well. The search without getObjects works fine with below function.

    this.data.filter(function(row){ 
        var flag; 
        for(var prop in (columns.length > 0 ? columns : row)){ 
          flag = false; 
          flag = row[columns.length > 0 ? columns[prop] : 
prop].toString().toLowerCase().indexOf(searchString.toString().toLowerCase()) > -1; 
          if(flag) 
          break; 
        } 
    return flag;

In above function I am not able to search within nested object (asset_info). And so I have been using getObject function which I found online.

Now the issue is I am not able to search including asset_info but not able to return its parent. For example in fiddle, if I search for emc, search should return 2nd object from data.

Update: still not able to return parent of a child where search string has been found

** Update 2 **

var data = [
{
  'booking_name': 'gtec/1101822/lmikdy/ls-rmea/oss11',
  'asset_count': 2,
  'pdg': 'Invalid',
  'user_area': 'Invalid',
  'deployment_number': 'Invalid',
  'spoc': 'invalid',
  'release': 'Invalid',
  'start_date': '2017-06-12 00:00:00',
  'end_date': '2017-06-16 00:00:00',
  'asset_info': [
    {
      'bams_id': 'BAMS-1001423507',
      'hostname': 'GTVOSS11',
      'status': 10,
      'site_location': 'IEAT01 Tipperary',
      'rack_number': 'VIRTUAL RACK',
      'rack_u_position': 0,
      'manufacturer': 'EMC',
      'model': 'VM',

    },
    {
      'bams_id': 'BAMS-1001368001',
      'hostname': 'None',
      'status': 10,
      'site_location': 'IEAT01 Tipperary',
      'rack_number': 'VIRTUAL RACK',
      'rack_u_position': 0,
      'manufacturer': 'HP',
      'model': 'HP BL460C GEN8',

    }
],
'full_name': 'Invalid (invalid)',
'email_address': 'Invalid'
},
{
  'booking_name': 'gtec/1101822/lmikdy/ls-rmea/oss11',
  'asset_count': 2,
  'pdg': 'Invalid',
  'user_area': 'Invalid',
  'deployment_number': 'Invalid',
  'spoc': 'invalid',
  'release': 'Invalid',
  'start_date': '2017-06-12 00:00:00',
  'end_date': '2017-06-16 00:00:00',
  'asset_info': [
    {
      'bams_id': 'BAMS-1001423507',
      'hostname': 'GTVOSS11',
      'status': 10,
      'site_location': 'IEAT01 Tipperary',
      'rack_number': 'VIRTUAL RACK',
      'rack_u_position': 0,
      'manufacturer': 'EMC',
      'model': 'VM',

    }
],
'full_name': 'Invalid (invalid)',
'email_address': 'Invalid'
}];

Here if I search for a string 'emc', it should return 2 objects. 1st object will have only one child as there is only one object has 'manufacturer' as 'emc'.

The output should be:

[
{
  'booking_name': 'gtec/1101822/lmikdy/ls-rmea/oss11',
  'asset_count': 2,
  'pdg': 'Invalid',
  'user_area': 'Invalid',
  'deployment_number': 'Invalid',
  'spoc': 'invalid',
  'release': 'Invalid',
  'start_date': '2017-06-12 00:00:00',
  'end_date': '2017-06-16 00:00:00',
  'asset_info': [
    {
      'bams_id': 'BAMS-1001423507',
      'hostname': 'GTVOSS11',
      'status': 10,
      'site_location': 'IEAT01 Tipperary',
      'rack_number': 'VIRTUAL RACK',
      'rack_u_position': 0,
      'manufacturer': 'EMC',
      'model': 'VM',

    }
],
'full_name': 'Invalid (invalid)',
'email_address': 'Invalid'
},
{
  'booking_name': 'gtec/1101822/lmikdy/ls-rmea/oss11',
  'asset_count': 2,
  'pdg': 'Invalid',
  'user_area': 'Invalid',
  'deployment_number': 'Invalid',
  'spoc': 'invalid',
  'release': 'Invalid',
  'start_date': '2017-06-12 00:00:00',
  'end_date': '2017-06-16 00:00:00',
  'asset_info': [
    {
      'bams_id': 'BAMS-1001423507',
      'hostname': 'GTVOSS11',
      'status': 10,
      'site_location': 'IEAT01 Tipperary',
      'rack_number': 'VIRTUAL RACK',
      'rack_u_position': 0,
      'manufacturer': 'EMC',
      'model': 'VM',

    }
],
'full_name': 'Invalid (invalid)',
'email_address': 'Invalid'
}];

How do I search for a string within an array of objects including nested object and return parent object if search string is found in child object ?

Valay
  • 1,991
  • 2
  • 43
  • 98
  • https://stackoverflow.com/questions/15523514/find-by-key-deep-in-a-nested-object – Simon Dragsbæk Jun 15 '17 at 07:18
  • @SimonPertersen I tried with the solution you suggested. But I am not able to return parent of a child object where search string has been found. Could you please look at this https://jsfiddle.net/7eL7t0d1/6/ – Valay Jun 15 '17 at 09:31

1 Answers1

5

You could use an iterative and recursive approach and return the result of the check and build new objects and arrays if the children matches the search value.

function getValue(item) {
    if (Array.isArray(item)) {
        return item.reduce(iterA, undefined);
    }
    if (item && typeof item === 'object') {
        return iterO(item);
    }
    if (typeof item !== 'object' && item.toString().toLowerCase().indexOf(search) !== -1) {
        return item;
    }
}

function iterO(o) {
    var temp = Object.keys(o).reduce(function (r, k) {
            var value = getValue(o[k]);
            if (value) {
                r = r || {};
                r[k] = value;
            }
            return r;
        }, undefined);

    if (temp) {
        Object.keys(o).forEach(function (k) {
            if (!(k in temp)) {
                temp[k] = o[k];
            }
        });
    }
    return temp;
}

function iterA(r, a) {
    var value = getValue(a);
    if (value) {
        r = r || [];
        r.push(value);
    }
    return r;
}

var data = [{ booking_name: "gtec/1101822/lmikdy/ls-rmea/oss11", asset_count: 2, pdg: "Invalid", user_area: "Invalid", deployment_number: "Invalid", spoc: "invalid", release: "Invalid", start_date: "2017-06-12 00:00:00", end_date: "2017-06-16 00:00:00", asset_info: [{ bams_id: "BAMS-1001423507", hostname: "GTVOSS11", status: 10, site_location: "IEAT01 Tipperary", rack_number: "VIRTUAL RACK", rack_u_position: 0, manufacturer: "EMC", model: "VM" }, { bams_id: "BAMS-1001368001", hostname: "None", status: 10, site_location: "IEAT01 Tipperary", rack_number: "VIRTUAL RACK", rack_u_position: 0, manufacturer: "HP", model: "HP BL460C GEN8" }], full_name: "Invalid (invalid)", email_address: "Invalid" }, { booking_name: "gtec/1101822/lmikdy/ls-rmea/oss11", asset_count: 2, pdg: "Invalid", user_area: "Invalid", deployment_number: "Invalid", spoc: "invalid", release: "Invalid", start_date: "2017-06-12 00:00:00", end_date: "2017-06-16 00:00:00", asset_info: [{ bams_id: "BAMS-1001423507", hostname: "GTVOSS11", status: 10, site_location: "IEAT01 Tipperary", rack_number: "VIRTUAL RACK", rack_u_position: 0, manufacturer: "EMC", model: "VM" }], full_name: "Invalid (invalid)", email_address: "Invalid" }],
    search = 'emc',
    result = data.reduce(iterA, undefined);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • that's great. it works fine. thanks a lot. how can I return parent with only child/children that has search string ? I mean not returning all child even if search string has been found in only one child. – Valay Jun 15 '17 at 11:02
  • 1
    do you mean the parent object? – Nina Scholz Jun 15 '17 at 11:34
  • yes parent with only child that has search string found. – Valay Jun 15 '17 at 11:38
  • for example if search string has found within 2 child out of 20 children, the function should return parent with 2 child only. currently it's returning parent with all 20 children. – Valay Jun 15 '17 at 11:40
  • I've updated data in fiddle https://jsfiddle.net/7eL7t0d1/7/. If I search for string 'emc', function should return 2 objects. first object should have only one child where manufacturer is emc. – Valay Jun 15 '17 at 11:46
  • did you able to make the function works in that way ? I am still not able to figure it out from the function you have created. – Valay Jun 15 '17 at 12:42
  • actually i don't know, what you really want. if the inner object has a sub string wiht the wanted part, the outer element is returned. – Nina Scholz Jun 15 '17 at 13:26
  • yes but if there are more than one inner object and sub string has found with only one inner (child) object then I need outer (parent) with only one inner (child) object. Not with all inner (child) object. – Valay Jun 15 '17 at 13:28
  • please define inner and outer object actually your structure is array0 object0 array1 object1 property. – Nina Scholz Jun 15 '17 at 13:30
  • I've given example in update 2 of the question description. – Valay Jun 15 '17 at 13:38
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/146772/discussion-between-valay-desai-and-nina-scholz). – Valay Jun 15 '17 at 13:38
  • could you help me with this https://stackoverflow.com/questions/44804322/php-deep-search-array-of-arrays-and-return-only-matching-elements – Valay Jun 29 '17 at 15:23
  • @Valay, sorry, can not help with php. – Nina Scholz Jun 29 '17 at 15:58