如何过滤对象的值可能包含null的数组?

时间:2019-04-24 16:39:01

标签: javascript

这是api响应的示例

[
    {
        "id": 1,
        "name": "Medicine1",
        "status": true,
        "location": "E1-2",
        "genericName": "Medicine1 Generic name",
        "laboratory": {
            "id": null,
            "name": null
        },
        "presentation": {
            "id": 1,
            "name": "Tabletas"
        },
        "measure": {
            "id": 1,
            "unit": "Gramos",
            "abbreviation": "g"
        },
        "quantity": 25,
        "percentage": null
    },
    {
        "id": 2,
        "name": "Medicine2",
        "status": true,
        "location": "E1-5",
        "genericName": "Medicine2 Generic",
        "laboratory": {
            "id": null,
            "name": null
        },
        "presentation": {
            "id": 2,
            "name": "Cremas"
        },
        "measure": {
            "id": 1,
            "unit": "Gramos",
            "abbreviation": "g"
        },
        "quantity": 500,
        "percentage": null
    },
    {
        "id": 3,
        "name": "Medicine3",
        "status": true,
        "location": "E1-2",
        "genericName": null,
        "laboratory": {
            "id": null,
            "name": null
        },
        "presentation": {
            "id": 3,
            "name": "Unguentos"
        },
        "measure": {
            "id": 3,
            "unit": "Libras",
            "abbreviation": "lb"
        },
        "quantity": 5,
        "percentage": null
    },
    {
        "id": 4,
        "name": "Medicine4",
        "status": true,
        "location": "E5-1",
        "genericName": null,
        "laboratory": {
            "id": null,
            "name": null
        },
        "presentation": {
            "id": 1,
            "name": "Tabletas"
        },
        "measure": {
            "id": 2,
            "unit": "Kilogramos",
            "abbreviation": "kg"
        },
        "quantity": 5,
        "percentage": null
    },
    {
        "id": 5,
        "name": "Medicine5",
        "status": true,
        "location": "E1-1",
        "genericName": null,
        "laboratory": {
            "id": null,
            "name": null
        },
        "presentation": {
            "id": 1,
            "name": "Tabletas"
        },
        "measure": {
            "id": 1,
            "unit": "Gramos",
            "abbreviation": "g"
        },
        "quantity": 5,
        "percentage": null
    },
    {
        "id": 6,
        "name": "Medicine5",
        "status": true,
        "location": "E1-1",
        "genericName": null,
        "laboratory": {
            "id": null,
            "name": null
        },
        "presentation": {
            "id": 1,
            "name": "Tabletas"
        },
        "measure": {
            "id": 1,
            "unit": "Gramos",
            "abbreviation": "g"
        },
        "quantity": 5,
        "percentage": null
    },
    {
        "id": 7,
        "name": "Medicine6",
        "status": true,
        "location": "E1-1",
        "genericName": null,
        "laboratory": {
            "id": null,
            "name": null
        },
        "presentation": {
            "id": 1,
            "name": "Tabletas"
        },
        "measure": {
            "id": 1,
            "unit": "Gramos",
            "abbreviation": "g"
        },
        "quantity": 5,
        "percentage": null
    },
    {
        "id": 8,
        "name": "Medicine7",
        "status": true,
        "location": "E1-1",
        "genericName": null,
        "laboratory": {
            "id": 3,
            "name": "Falcon"
        },
        "presentation": {
            "id": 4,
            "name": "Gotas"
        },
        "measure": {
            "id": 1,
            "unit": "Gramos",
            "abbreviation": "g"
        },
        "quantity": 5,
        "percentage": null
    }
]

如您所见,实验室键,percentage和genericName键可以具有空值。

我需要根据应该与每个值进行比较的标准来过滤此响应

这是过滤器代码

const criteria = 'some text';

fetchResource('medicines').then(medicines => {
    const results = medicines.filter(medicine => {
        return (
            medicine.name.toLowerCase().includes(criteria) ||
            medicine.genericName.toLowerCase().includes(criteria) ||
            medicine.presentation.name
                .toLowerCase()
                .includes(criteria) ||
            medicine.measure.unit.toLowerCase().includes(criteria) ||
            medicine.measure.abbreviation
                .toLowerCase()
                .includes(criteria) ||
            medicine.location.toLowerCase().includes(criteria)
        );
    });

    const helper = makeHelper();

    helper.render(results);
});

在后端,我考虑过在没有值的情况下从响应中排除提及的键。我还没有尝试过,但我知道那会起作用

感谢您在如何处理此案方面的建议

4 个答案:

答案 0 :(得分:3)

这里还有其他答案,建议使用JSON.stringify将整个对象转换为字符串,但这不是一个很好的解决方案。由于每个对象都有一个名为generic的属性,因此将不可能搜索genericName。还有另一种使用stringify的方法,它更优雅一些,并且可以利用replacer回调。

例如:

const results = medicines.filter(m => {
  var isMatch = false;
  JSON.stringify(m, (key, value) => {
    if (typeof value === "string" && value.toLowerCase().includes(criteria)) {
      isMatch = true;
    }
    return value;
  });
  return isMatch;
});

results将仅包含medicines中包含某些 value 的条目,该条目是与给定过滤器匹配的字符串。您可以扩展此逻辑以包括数字值,例如id,或排除某些您不感兴趣的键,例如abbreviation

这是一个实现一些更高级逻辑的快速演示。您当然要对其进行调整以满足您的确切需求:

const medicines = [{
    "id": 1,
    "name": "Medicine1",
    "status": true,
    "location": "E1-2",
    "genericName": "Medicine1 Generic name",
    "laboratory": { "id": null, "name": null },
    "presentation": { "id": 1, "name": "Tabletas" },
    "measure": { "id": 1, "unit": "Gramos", "abbreviation": "g" },
    "quantity": 25,
    "percentage": null
  },
  {
    "id": 2,
    "name": "Medicine2",
    "status": true,
    "location": "E1-5",
    "genericName": "Medicine2 Generic",
    "laboratory": { "id": null, "name": null },
    "presentation": { "id": 2, "name": "Cremas" },
    "measure": { "id": 1, "unit": "Gramos", "abbreviation": "g" },
    "quantity": 500,
    "percentage": null
  },
  {
    "id": 3,
    "name": "Medicine3",
    "status": true,
    "location": "E1-2",
    "genericName": null,
    "laboratory": { "id": null, "name": null },
    "presentation": { "id": 3, "name": "Unguentos" },
    "measure": { "id": 3, "unit": "Libras", "abbreviation": "lb" },
    "quantity": 5,
    "percentage": null
  },
  {
    "id": 4,
    "name": "Medicine4",
    "status": true,
    "location": "E5-1",
    "genericName": null,
    "laboratory": { "id": null, "name": null },
    "presentation": { "id": 1, "name": "Tabletas" },
    "measure": { "id": 2, "unit": "Kilogramos", "abbreviation": "kg" },
    "quantity": 5,
    "percentage": null
  },
  {
    "id": 5,
    "name": "Medicine5",
    "status": true,
    "location": "E1-1",
    "genericName": null,
    "laboratory": { "id": null, "name": null },
    "presentation": { "id": 1, "name": "Tabletas" },
    "measure": { "id": 1, "unit": "Gramos", "abbreviation": "g" },
    "quantity": 5,
    "percentage": null
  },
  {
    "id": 6,
    "name": "Medicine5",
    "status": true,
    "location": "E1-1",
    "genericName": null,
    "laboratory": { "id": null, "name": null },
    "presentation": { "id": 1, "name": "Tabletas" },
    "measure": { "id": 1, "unit": "Gramos", "abbreviation": "g" },
    "quantity": 5,
    "percentage": null
  },
  {
    "id": 7,
    "name": "Medicine6",
    "status": true,
    "location": "E1-1",
    "genericName": null,
    "laboratory": { "id": null, "name": null },
    "presentation": { "id": 1, "name": "Tabletas" },
    "measure": { "id": 1, "unit": "Gramos", "abbreviation": "g" },
    "quantity": 5,
    "percentage": null
  },
  {
    "id": 8,
    "name": "Medicine7",
    "status": true,
    "location": "E1-1",
    "genericName": null,
    "laboratory": { "id": 3, "name": "Falcon" },
    "presentation": { "id": 4, "name": "Gotas" },
    "measure": { "id": 1, "unit": "Gramos", "abbreviation": "g" },
    "quantity": 5,
    "percentage": null
  }
];

const btn = document.getElementById("go");
const inp = document.getElementById("search");
btn.addEventListener('click', () => {
  const criteria = inp.value.toLowerCase();
  const results = medicines.filter(m => {
    var isMatch = false;
    JSON.stringify(m, (key, value) => {
      // Search 'id' values
      if (key === "id" && value !== null && value.toString().includes(criteria)) {
        isMatch = true;
        // Ignore 'abbreviation'
      } else if (key !== "abbreviation") {
        // Search all other string values
        if (typeof value === "string" && value.toLowerCase().includes(criteria)) {
          isMatch = true;
        }
      }

      return value;
    });
    return isMatch;
  });
  console.log(results);
});
<input id="search" type="search" placeholder="filter" /><button id="go">Go</button><br>
<code>

答案 1 :(得分:1)

如果medicine.genericName.toLowerCase()字段不是字符串,当前您的代码将在genericName上出错。为避免这种情况,您可以尝试以下方法之一:

恢复默认设置:
(medicine.genericName || '').toLowerCase().includes(criteria)

先检查值:
(medicine.genericName && medicine.genericName.toLowerCase().includes(criteria))

答案 2 :(得分:1)

弄清楚您要如何处理该示例有点困难,但是我假设您要检查API响应中多个键的值是否包含子字符串条件?

如果是这样,您可以尝试以下方法:

fetchResource('medicines').then(medicines => {
    const results = medicines.filter(medicine => {
        for (var key in medicine){
            if((typeof(medicine[key] == 'string' || typeof(medicine[key] == 'int') && medicine[key].toString().toLowerCase().includes(criteria)){
                return true
            }
            else if(typeof(medicine[key]) === 'object'){
                for(var subkey in medicine[key]){
                    if((typeof(medicine[key][subkey]) == 'string' || typeof(medicine[key][subkey]) === 'int') && medicine[key][subkey].toString().toLowerCase().includes(criteria)){
                        return true
                    }
                }          
            }
        }
        return false
    })
})

这显然比对所有属性名称进行硬编码要干净得多。

答案 3 :(得分:0)

正如我之前所说,在您的数组中使用forEach;遵循过滤功能; 使用JSON.stringify,以便您在行中看到所有属性; 应用模式作为条件

var yourCriteria = ""; // or any Regex
var yourArray = [];
var newArray = []; 
yourArray.forEach(function(e){
 if (JSON.stringify(e).toLowerCase().indexOf(yourCriteria) < 0) 
     newArray.push(e);
})