如何根据来自另一个对象的匹配值对对象数组进行筛选或自定义筛选

时间:2022-01-11 07:54:00

I implemented an advance search with 15 input fields in AngularJS.

我用AngularJS实现了15个输入字段的提前搜索。

In the page load itself the result set is return from database in JSON format and i need to do the filter in client side only.

在页面加载本身中,结果集以JSON格式从数据库返回,我只需要在客户端进行筛选。

The input criteria's equivalent column is available in the result set and i need to check in its respective column only.

输入条件的等效列在结果集中是可用的,我只需要检查它各自的列。

I am converting each column by JSON.stringify() and check with the search params like the below :

我将JSON.stringify()转换每一列,并使用如下所示的搜索参数:

$scope.filteredData = $scope.actualData.filter(function(item) {
    return JSON.stringify(item.FirstName).toLowerCase().indexOf(lowerFirstName) != -1 &&
    JSON.stringify(item.LastName).toLowerCase().indexOf(lowerLastName) != -1 &&
    JSON.stringify(item.EmailAddress).toLowerCase().indexOf(lowerEmailAddress) != -1 &&
    JSON.stringify(item.Address1).toLowerCase().indexOf(lowerAddress1) != -1 &&
    JSON.stringify(item.Address2).toLowerCase().indexOf(lowerAddress2) != -1;
    ...... etc // upto 15 fields
});

Since i have the 15 input fields and the actual result set contains a minimum of 50,000 records.

因为我有15个输入字段,而实际的结果集包含至少50,000条记录。

So converting each record's each column by JSON.stringify() and check with search params will surely cause the performance issue.

因此,通过JSON.stringify()转换每个记录的每一列,并使用搜索参数对其进行检查,肯定会导致性能问题。

Is there any other way to achieve the filtering in client side with other approach.

是否有其他方法来实现客户端过滤。

I posted a sample code in Plunker with 5 input fields only : http://plnkr.co/edit/nUWZEbGvz7HG6gb91YZP

我在Plunker中发布了一个只有5个输入字段的示例代码:http://plnkr.co/edit/nUWZEbGvz7HG6gb91YZP

2 个解决方案

#1


2  

sylwester's answer is the normal way you'd filter things. Your code looks like you want to filter down to only the object that matches every input field. You code attempts to find an object where every property matches the searchParams object. At that point, I don't see what benefit there is to finding that object, because the user already created the object again! Nonetheless, here's a proper version of your code:

sylwester的答案是你过滤事物的正常方式。您的代码看起来似乎只希望过滤到与每个输入字段匹配的对象。编写代码试图找到一个对象,其中每个属性都与searchParams对象匹配。在这一点上,我看不出找到那个对象有什么好处,因为用户已经再次创建了对象!尽管如此,这里有一个合适的代码版本:

Live demo here.

现场演示。

<div ng-repeat="data in actualData | filter:searchData()">
 $scope.searchData = function() {
    return function(item) {
      return Object.keys(item).every(function(key) {
        // skip the $$hashKey property Angular adds to objects
        if (key === '$$hashKey') { return true; }
        var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
        return item[key].toLowerCase() === $scope.searchParams[searchKey].toLowerCase();
      });
    };
  };

You really need to limit the data coming from the server for the browser's sake and for the server's sake. It's easy to implement a LIMIT, OFFSET system. It sounds like, overall, you just need to be able to query the server for a certain record.

为了浏览器和服务器,您确实需要限制来自服务器的数据。它很容易实现一个限制,偏移系统。总的来说,您需要能够查询服务器上的某条记录。

From your comments, it seems you definitely want Angular's built in filter filter:searchParams, and just capitalize your searchParams models to match your data. For fun, I'll include more options for finer tuning.

从你的评论来看,似乎你肯定想要角的内置过滤器:searchParams,并只是大写您的searchParams模型以匹配您的数据。为了好玩,我将提供更多的选项来进行更好的调优。

This one almost mimics filter:searchParams. You can change > 1 to adjust when the partial matching kicks in, or have it return true only when both items are strictly equal === to disable partial matching. The difference here is that all items are hidden until matched, whereas filter:searchParams will show all items and then remove what doesn't match.

这个几乎是模仿过滤器:searchParams。您可以更改> 1以在部分匹配开始时进行调整,或者仅在两个项严格相等=== ==时返回true以禁用部分匹配。这里的不同之处在于,所有的项都被隐藏直到匹配,而filter:searchParams将显示所有的项,然后删除不匹配的项。

Live demo here.

现场演示。

  $scope.searchData = function() {
    return function(item) {
      return Object.keys(item).some(function(key) {
        if (key === '$$hashKey') { return false; }
        var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
        var currentVal = $scope.searchParams[searchKey].toLowerCase();
        var match = item[key].toLowerCase().match(currentVal);
        return currentVal.length > 1 && match;
      });
    };
  };

Lastly, to perfectly mimic filter:searchParams, you'd just put in a check to NOT filter the items until there is user input and the input is long enough to start the partial match.

最后,为了完美地模拟过滤器:searchParams,您只需输入一个检查,直到用户输入和输入足够长,才能开始部分匹配为止。

Live demo here.

现场演示。

  $scope.searchData = function() {
    var partialMatchLength = 2;
    return function(item) {
      var shouldFilter = Object.keys($scope.searchParams).some(function(key) {
        return $scope.searchParams[key] && $scope.searchParams[key].length >= partialMatchLength;
      });
      if (!shouldFilter) { return true; }
      return Object.keys(item).some(function(key) {
        if (key === '$$hashKey') { return false; }
        var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
        var currentVal = $scope.searchParams[searchKey].toLowerCase();
        var match = item[key].toLowerCase().match(currentVal);
        return currentVal.length >= partialMatchLength && match;
      });
    };
  };

#2


1  

First of all you ng-repeter with 50.000 records more likely is going to kill your browser, so you should thing about pagination. Secondly you can easy filter your data using angular filter please see that demo

首先,有50000个记录的ng-repeter可能会杀死你的浏览器,所以你应该考虑分页。第二,你可以很容易地用角滤波器过滤你的数据,请看演示

http://plnkr.co/edit/R8b8G4xCMSQmX1144UJG?p=preview

http://plnkr.co/edit/R8b8G4xCMSQmX1144UJG?p=preview

<div ng-controller="ListCtrl">
    <br />
    First Name:
    <input type="text" id="txtFirstname" ng-model="searchParams.FirstName">
    <br/>Last Name:
    <input type="text" id="txtLastname" ng-model="searchParams.LastName">
    <br/>Email Address:
    <input type="text" id="txtEmailAddress" ng-model="searchParams.EmailAddress">
    <br/>Address 1:
    <input type="text" id="txtAddress1" ng-model="searchParams.Address1">
    <br/>Address 2:
    <input type="text" id="txtAddress2" ng-model="searchParams.Address2">
    <br/>
    <button class="btn btn-primary" ng-click="searchData()">Search</button>
    <br />
    <hr />
    <b>Filtered Data(s):</b>
    <div ng-repeat="data in actualData | filter:searchParams ">
      <span ng-bind="data.FirstName"></span>
      <span ng-bind="data.LastName"></span> |
      Address : {{data.Address1}}
    </div>
    <hr />

  </div>

#1


2  

sylwester's answer is the normal way you'd filter things. Your code looks like you want to filter down to only the object that matches every input field. You code attempts to find an object where every property matches the searchParams object. At that point, I don't see what benefit there is to finding that object, because the user already created the object again! Nonetheless, here's a proper version of your code:

sylwester的答案是你过滤事物的正常方式。您的代码看起来似乎只希望过滤到与每个输入字段匹配的对象。编写代码试图找到一个对象,其中每个属性都与searchParams对象匹配。在这一点上,我看不出找到那个对象有什么好处,因为用户已经再次创建了对象!尽管如此,这里有一个合适的代码版本:

Live demo here.

现场演示。

<div ng-repeat="data in actualData | filter:searchData()">
 $scope.searchData = function() {
    return function(item) {
      return Object.keys(item).every(function(key) {
        // skip the $$hashKey property Angular adds to objects
        if (key === '$$hashKey') { return true; }
        var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
        return item[key].toLowerCase() === $scope.searchParams[searchKey].toLowerCase();
      });
    };
  };

You really need to limit the data coming from the server for the browser's sake and for the server's sake. It's easy to implement a LIMIT, OFFSET system. It sounds like, overall, you just need to be able to query the server for a certain record.

为了浏览器和服务器,您确实需要限制来自服务器的数据。它很容易实现一个限制,偏移系统。总的来说,您需要能够查询服务器上的某条记录。

From your comments, it seems you definitely want Angular's built in filter filter:searchParams, and just capitalize your searchParams models to match your data. For fun, I'll include more options for finer tuning.

从你的评论来看,似乎你肯定想要角的内置过滤器:searchParams,并只是大写您的searchParams模型以匹配您的数据。为了好玩,我将提供更多的选项来进行更好的调优。

This one almost mimics filter:searchParams. You can change > 1 to adjust when the partial matching kicks in, or have it return true only when both items are strictly equal === to disable partial matching. The difference here is that all items are hidden until matched, whereas filter:searchParams will show all items and then remove what doesn't match.

这个几乎是模仿过滤器:searchParams。您可以更改> 1以在部分匹配开始时进行调整,或者仅在两个项严格相等=== ==时返回true以禁用部分匹配。这里的不同之处在于,所有的项都被隐藏直到匹配,而filter:searchParams将显示所有的项,然后删除不匹配的项。

Live demo here.

现场演示。

  $scope.searchData = function() {
    return function(item) {
      return Object.keys(item).some(function(key) {
        if (key === '$$hashKey') { return false; }
        var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
        var currentVal = $scope.searchParams[searchKey].toLowerCase();
        var match = item[key].toLowerCase().match(currentVal);
        return currentVal.length > 1 && match;
      });
    };
  };

Lastly, to perfectly mimic filter:searchParams, you'd just put in a check to NOT filter the items until there is user input and the input is long enough to start the partial match.

最后,为了完美地模拟过滤器:searchParams,您只需输入一个检查,直到用户输入和输入足够长,才能开始部分匹配为止。

Live demo here.

现场演示。

  $scope.searchData = function() {
    var partialMatchLength = 2;
    return function(item) {
      var shouldFilter = Object.keys($scope.searchParams).some(function(key) {
        return $scope.searchParams[key] && $scope.searchParams[key].length >= partialMatchLength;
      });
      if (!shouldFilter) { return true; }
      return Object.keys(item).some(function(key) {
        if (key === '$$hashKey') { return false; }
        var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
        var currentVal = $scope.searchParams[searchKey].toLowerCase();
        var match = item[key].toLowerCase().match(currentVal);
        return currentVal.length >= partialMatchLength && match;
      });
    };
  };

#2


1  

First of all you ng-repeter with 50.000 records more likely is going to kill your browser, so you should thing about pagination. Secondly you can easy filter your data using angular filter please see that demo

首先,有50000个记录的ng-repeter可能会杀死你的浏览器,所以你应该考虑分页。第二,你可以很容易地用角滤波器过滤你的数据,请看演示

http://plnkr.co/edit/R8b8G4xCMSQmX1144UJG?p=preview

http://plnkr.co/edit/R8b8G4xCMSQmX1144UJG?p=preview

<div ng-controller="ListCtrl">
    <br />
    First Name:
    <input type="text" id="txtFirstname" ng-model="searchParams.FirstName">
    <br/>Last Name:
    <input type="text" id="txtLastname" ng-model="searchParams.LastName">
    <br/>Email Address:
    <input type="text" id="txtEmailAddress" ng-model="searchParams.EmailAddress">
    <br/>Address 1:
    <input type="text" id="txtAddress1" ng-model="searchParams.Address1">
    <br/>Address 2:
    <input type="text" id="txtAddress2" ng-model="searchParams.Address2">
    <br/>
    <button class="btn btn-primary" ng-click="searchData()">Search</button>
    <br />
    <hr />
    <b>Filtered Data(s):</b>
    <div ng-repeat="data in actualData | filter:searchParams ">
      <span ng-bind="data.FirstName"></span>
      <span ng-bind="data.LastName"></span> |
      Address : {{data.Address1}}
    </div>
    <hr />

  </div>