Javascript - возвращает родительский элемент с единственным дочерним элементом, который соответствует заданной строке поиска в массиве объектов с вложенным объектом

Это следующий вопрос из моего предыдущего вопроса. Из полученного ответа я могу выполнить поиск внутри вложенного объекта в массиве объектов.

Скачайте скрипку, например.

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'
}];

Здесь, когда я ищу строку 'emc', функция возвращает два объекта, которые являются правильными. Но "emc" как "производитель" находится в дочернем объекте. И каждый дочерний объект не удовлетворяет этому условию. Результат, который я ищу, например, "emc", должен возвращать 2 родительских объекта. У первого родительского объекта должен быть только один ребенок (у другого ребенка есть "hp" в качестве производителя). Второй родительский объект должен иметь один дочерний элемент, соответствующий строке поиска.

Я попытался создать новый объект с результатом поиска, но не смог заставить его работать.

Как вернуть родительский объект только с дочерним элементом, который удовлетворяет заданной строке поиска?

Вот чат моего предыдущего вопроса, который поможет понять проблему и требования.

Ответ 1

Вы можете использовать итеративный и рекурсивный подход и вернуть результат проверки и построить новые объекты и массивы, если они соответствуют значению поиска.

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; }

Ответ 2

Я не уверен, насколько глубоко ваш подход должен идти, но это должно сделать трюк

он сделает копию каждой строки, когда имеет дочерний элемент, и заменит набор только соответствующими значениями

function filterSet(dataSet, matchFn) {
  return dataSet.reduce((current, row) => {
    if (typeof row === 'object') {
      for (let prop in row) {
        if (Array.isArray(row[prop])) {
          var set = filterSet(row[prop], matchFn);
          if (set && set.length > 0) {
            // copy the row, replace the array property with the results
            current.push( Object.assign({}, row,
              { [prop]: set }
            ) );
            // since the full row is now in there
            // no need to check more
            break;
          }
        } else if (matchFn(row[prop])) {
            // copy not ref
            current.push( Object.assign( {}, row ) );
            break;
          }
      }
    }
    return current;
  }, []);
}

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'
  }
];

console.log(filterSet(data, (i) => {
  return i.toString().toLowerCase().indexOf('emc') >= 0;
}));

console.log(filterSet(data, (i) => {
  return i.toString().toLowerCase().indexOf('invalid') >= 0;
}));