2016-01-07 40 views
2

我在我的Laravel應用程序中創建了一個API來提取所有客戶端(3000+)的詳細信息,以便我可以使用我的AngularJS自動填充表單搜索其名稱/地址/電話號碼等。Laravel API - 拉取大量數據(json)

API輸出約1,000Kb的客戶端數據(json)。如果我沒有獲取所有數據,我可以認爲在搜索框中鍵入他的名字時,客戶端不存在,所以我希望能夠加載它們。

一切工作正常,但1,000KB下載是一個緩慢的。 AngularJS雖然處理得好。如果我有10,000個客戶呢?

哪裏應該增加這種性能取:

  • Laravel口才查詢,是否有一種方式來獲得在這種情況下在卡盤的數據?
  • 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":"[email protected]" 
     }, 
     { 
     "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":"[email protected]" 
     }, 
     { 
     "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":"[email protected]" 
     }, 
     { 
     "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":"[email protected]" 
     }, 
     { 
     "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":"[email protected]" 
     } 
+2

您只提取您需要的信息嗎?看起來如果你只是做一個自動完成的,你所需要的只是名字。很難相信你需要3000個客戶端的數據。 – user3158900

+0

我已經在上面添加了我的代碼和輸出的示例。例如,如果我將名稱「address_1」更改爲「a1」,將「phone_number_1」更改爲「p1」,則可能會損失幾個Kb。但除此之外...... – user3489502

回答

0

是啊...可能不是一個好主意,要求對自動完成功能的1 MB的下載。你有兩個主要選項:

  1. 下載名稱和ID的完整列表,忽略所有其他參數,否則使用當前的方法
  2. 運行在一個AJAX調用您自動完成

選項1適用於較小的列表,您當然可以設計一個比當前使用的小得多的有效負載的API調用。

一旦您的應用程序擴展到一定的大小,選項2將成爲唯一的解決方案。缺點是它不如將所有內容加載到內存中那麼快。

+0

謝謝!我想我只能檢索id和name,所以json的輸出會小很多。我以爲我可以使用gzip(讀取某處)壓縮json,使它變得更小 – user3489502

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....

這將是一個最小的繃帶到這個問題,我不一定會推薦重命名鍵返回。

+0

謝謝我同意,但我真的很喜歡打字並獲得我想輸入的結果而不用刷新的想法。實際上,它現在工作正常,只是下載整個json的時間,它會延遲幾秒(2-3秒)。但我同意,當我的名單變得更大時,它會變得更慢。我想我可以使用gzip(讀取某處)來壓縮json,使其變小 – user3489502