Laravel API - 提取大量数据(json)

时间:2016-01-07 20:16:25

标签: php laravel laravel-5 eloquent

我在Laravel应用程序中创建了一个API来提取所有客户端(3000+)的详细信息,以便我可以使用我的AngularJS自动填充表单来搜索他们的姓名/地址/电话号码等。

API输出大约1,000Kb的客户端数据(json)。如果我没有获取所有数据,我可以认为在搜索框中输入他的名字时客户端不存在,所以我希望能够加载它们。

一切正常,但1000Kb的下载速度很慢。虽然AngularJS处理得很好。如果我有10,000个客户怎么办?

我应该在哪里提高此抓取的性能:

  • Laravel Eloquent查询,有没有办法在这种情况下获取数据?
  • Php(gzip)减少拉取数据的大小?
  • AngularJS在第一行下载后立即工作?

以下是我使用的代码:

API控制器

public function index()
{
    $clients = Client::where('business_id', '=', \Auth::user()->business_id)->orderBy('updated_at', 'DESC')->get();

    return  Response::json([
       'clients' => $this->transformClientCollection($clients)
    ], 200);
}

public function transformClientCollection($clients)
{
    return array_map([$this, 'transformClient'], $clients->toArray());
}

public function transformClient($clients)
{

    return [
        'clientid' => $clients['id'],
        'first_name' => $clients['first_name'],
        'last_name' => $clients['last_name'],
        'address_1' => $clients['address_1'],
        'address_2' => $clients['address_2'],
        'city' => $clients['city'],
        'state' => $clients['state'],
        'postal_code' => $clients['postal_code'],
        'phone_number_1' => $clients['phone_number_1'],
        'phone_number_2' => $clients['phone_number_2'],
        'email' => $clients['email']
    ];
}

AngularJS(html文件)

<div ng-app="instantsearch">
    <div ng-controller="instantSearchCtrl">

        <div class="row">
        <div class="col-sm-12">
            <input type="text" class="form-control search" ng-model="searchString" placeholder="Enter your search terms" /> 
        </div>
        </div>

        <div class="row data-ctrl" ng-repeat="i in items | filter:searchString | limitTo:20 ">
          <div class="col-sm-12">
           @{{ i.first_name }} @{{ i.last_name }} @{{ i.address_1 }} @{{ i.address_2 }} @{{ i.city }} @{{ i.state }} @{{ i.phone_number_1 }} @{{ i.phone_number_2 }} @{{ i.email }}
          </div>             
        </div>

    </div>
</div>

AngularJS(JS档案)

var app = angular.module('instantsearch',[]);

app.controller('instantSearchCtrl',function($scope,$http,$location){

    var urlapiclients = $location.protocol() + "://" + $location.host() + "/api/clients" ;

    $http.get(urlapiclients).success(function(data, status, headers, config) {
        $scope.items = data.clients;

    }).error(function(data, status, headers, config) {
        console.log("No data found..");
  });
});


app.filter('searchFor', function(){
    return function(arr, searchString){
        if(!searchString){
            return arr;
        }
        var result = [];
        searchString = searchString.toLowerCase();
        angular.forEach(arr, function(item){
            if(item.first_name.toLowerCase().indexOf(searchString) !== -1){
            result.push(item);
        }
        });
        return result;
    };
}); 

JSON输出

   "clients":[
      {
         "clientid":4981,
         "first_name":"Sid",
         "last_name":"Hodkiewicz",
         "address_1":"6659 Hackett Ways",
         "address_2":"",
         "city":"New Estherville",
         "state":"Tennessee",
         "postal_code":"27281-0870",
         "phone_number_1":"00700300842",
         "phone_number_2":"",
         "email":"hNitzsche@Stokes.biz"
      },
      {
         "clientid":4982,
         "first_name":"Braulio",
         "last_name":"Bechtelar",
         "address_1":"7558 Anne Land Suite 876",
         "address_2":"",
         "city":"Rauview",
         "state":"Alabama",
         "postal_code":"01837-9601",
         "phone_number_1":"1-017-001-8215",
         "phone_number_2":"",
         "email":"nBaumbach@gmail.com"
      },
      {
         "clientid":4983,
         "first_name":"Loma",
         "last_name":"Dibbert",
         "address_1":"805 Jones Fields Suite 411",
         "address_2":"",
         "city":"Lake Billychester",
         "state":"New Jersey",
         "postal_code":"69315-4595",
         "phone_number_1":"(691)511-6275x891",
         "phone_number_2":"",
         "email":"dHegmann@Bashirian.net"
      },
      {
         "clientid":4984,
         "first_name":"Verla",
         "last_name":"Schulist",
         "address_1":"89529 Bode Village Suite 344",
         "address_2":"",
         "city":"West Jessy",
         "state":"Virginia",
         "postal_code":"69116",
         "phone_number_1":"(248)211-3643",
         "phone_number_2":"",
         "email":"Friesen.Ruthie@Hand.biz"
      },
      {
         "clientid":4985,
         "first_name":"Jimmie",
         "last_name":"Fadel",
         "address_1":"4355 Marquardt Heights",
         "address_2":"",
         "city":"South Conrad",
         "state":"District of Columbia",
         "postal_code":"55751",
         "phone_number_1":"(414)901-2495",
         "phone_number_2":"",
         "email":"Koepp.Wayne@yahoo.com"
      }

2 个答案:

答案 0 :(得分:0)

是的......要求1 MB下载自动完成功能可能不是一个好主意。您有两个主要选择:

  1. 下载完整的名称和ID列表,忽略所有其他参数,否则使用您当前的方法
  2. 在AJAX通话中运行自动填充
  3. 选项1适用于较小的列表,您当然可以使用比当前使用的有效载荷小得多的API调用。

    一旦您的应用程序扩展到一定的大小,选项2就成为唯一的解决方案。缺点是它不如将所有内容加载到内存中那么快。

答案 1 :(得分:0)

返回数据库中的每一行只是为了在Javascript中搜索它似乎有点过分。目前它可能只有3000个客户端,但我假设这个表是为了随着时间的推移而增长,并且随着时间的推移只会越来越慢。

实现此目的的最佳方法是仅返回与从Javascript应用程序传递的搜索查询匹配的客户端。例如,您可以发出请求:

http://www.example.com/api/v1/clients?search=foo

在服务器端,您可以执行以下操作:

$search = '%'.Input::get('search').'%';

// Just a few of the columns to search
$clients = Clients::where('first_name', 'LIKE', $search)
                   ->orWhere('last_name', 'LIKE', $search)
                   ->orWhere('state', 'LIKE', $search)
                   ->take(10)
                   ->get();

请记住,减少收集大小会减少从MySQL服务器传递到PHP(可能本身很慢)以及通过网络传递给Angular应用程序的数量。

回应你的评论:

I've added examples of my code and output above. I could lose a few Kb if I changed the names address_1 to a1 and phone_number_1 to p1 for example, but besides that....

这对问题是一个最小的绑定,我不一定建议重命名返回的密钥。