【问题标题】:Server side pagination with limited number of requests请求数量有限的服务器端分页
【发布时间】:2018-06-20 18:26:36
【问题描述】:

我的前端是 Angular5。后端是 REST API NODE.JS,数据库是 POSTGRES。

我的 postgres 中名为组织的表包含 100k ( 100 000) 行。

我有一个表格,其中包含所有组织的列表以及组织名称、位置等信息。

此时我的前端仅显示 50 个组织。我已经控制台记录了这一点,我的后端只发送了 50 个数组。

我的目标是使用服务器端分页在前端表中显示所有组织(其中 100 000 个)。

已经为显示的当前值进行了分页,其中有 50 个。代码如下

有效的前端表(当前仅显示从后端发送的 50 个组织)

 <div class="card-body">
      <div class="row">

            <div class="table-col">
                <div class="card table">
                    <div class="row header">
                        <div class="col col-md-6">Name</div>
                        <div class="col col-md-2">ID</div>
                        <div class="col col-md-2">Location</div>
                        <div class="col col-md-2">Person in charge</div>
                    </div>
                    <div *ngFor="let group of organizations">
                        <div *ngIf="group.name == 'all'">
                            <div class="row content-row" *ngFor="let organization of group.array |  search: term | orderBy: order | paginate: {itemsPerPage: 13, currentPage:page1, id: '1'}"
                                [routerLink]="['/organization/edit', organization.id]">
                                <div class="col col-md-6">{{organization.name}}</div>
                                <div class="col col-md-2">{{organization.id}}</div>
                                <div class="col col-md-2"  *ngIf="organization.place?.fullName != null">{{organization.place?.fullName}}</div>
                                <div class="col col-md-2"  *ngIf="organization.place?.fullName == null"><span class="badge badge-danger">-- N/A -- </span></div>
                                <div *ngIf="organization.person?.fullname != null" class="col col-md-2">{{organization.person?.fullname}}

                                </div>
                                 <div *ngIf="organization.person?.fullname == null" class="col col-md-2"><span class="badge badge-danger">-- N/A -- </span></div> 


                            </div>
                        </div>
                        <div *ngIf="group.name != 'all'">
                            <div class="row content-row">
                                <div class="col col-md-12 group-name" (click)="toggleGroup(group.name)">{{group.name + ':'}}</div>
                            </div>
                            <div *ngIf="showGroup == group.name">
                                <div class="row content-row" *ngFor="let organization of group.array | search: term |   paginate: {itemsPerPage: 5, currentPage:page2, id: '2'}"
                                    [routerLink]="['/organization/edit', organization.id]">
                                    <div class="col col-md-6" style="padding-left:23px;">{{organization.name}}</div>
                                    <div class="col col-md-2">{{organization.id}}</div>
                                    <div class="col col-md-2">{{organization.place?.fullName}}</div>
                                    <div class="col col-md-2">{{organization.person?.fullname}}
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div *ngIf="!(organizations[0].array.length > 0)" class="row noResults">
                        <label>No results..</label>
                    </div>
                    <div *ngIf="organizations[0].name == 'all'" class="paggination-row">
                        <div class="paggination">
                            <pagination-controls (pageChange)="page1 = $event" id="1" maxSize="5" directionLinks="true" autoHide="true" previousLabel="Previous"
                                nextLabel="Next">
                            </pagination-controls>
                        </div>
                    </div>
                    <div *ngIf="organizations[0].name != 'all' && showGroup != ''" class="paggination-row">
                        <div class="paggination">
                            <pagination-controls (pageChange)="page2 = $event" id="2" maxSize="5" directionLinks="true" autoHide="true" previousLabel="Previous"
                                nextLabel="Next">
                            </pagination-controls>
                        </div>
                    </div>
                </div>
            </div>
        </div>
      </div>

现在在我的配置中的后端我有以下代码:

   "host": "0.0.0.0",
      "port": 3030,
      "public": "../public/",
      "paginate": {
          "default": 50,
        "max": 50
      },

注意:主机 ip 故意更改。 分页是为什么我的前面只有 100 000 个值时才收到 50 个值的原因。

现在,如果我继续将默认值和最大值更改为 100k,我的前端应该会显示所有组织,但可能会在执行此操作的过程中使客户端和服务器崩溃。

如果我将分页设置为 false,那也无济于事。

现在我想知道如何才能保持有限的请求,例如 50 或 100(所以我的服务器还活着),但仍然使用服务器端分页或任何必要的方式在我的前端显示所有组织。

感谢您提供任何帮助,非常感谢您抽出宝贵时间阅读本文。

edit1:加载所有组织的服务:

import { Injectable } from '@angular/core';
import { Http, Headers } from "@angular/http";
import 'rxjs/add/operator/map';
import { AppSettings } from '../../../../../../app.settings';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

//service made to comunicate with backend
@Injectable()
export class CreateOrganizacijeService {
    private dataSource = new BehaviorSubject<any>("default")
    currentData = this.dataSource.asObservable();

    constructor(
        private http: Http
    ) { }

    updateData(data) {
        this.dataSource.next(data);
    }

    getAll() {
        let headers = new Headers();
        let token = localStorage.getItem('feathers-jwt');

        headers.append('Content-Type', 'application/json');
        headers.append('Authorization', 'Bearer ' + token)
        return this.http.get(AppSettings.API_ENDPOINT + '/organization', { headers: headers }).map(res => res.json())
    }

    getOne(id) {
        let headers = new Headers();
        let token = localStorage.getItem('feathers-jwt');

        headers.append('Content-Type', 'application/json');
        headers.append('Authorization', 'Bearer ' + token)
        return this.http.get(AppSettings.API_ENDPOINT + '/organization?id=' + id, { headers: headers }).map(res => res.json())
    }

    createNew(organization) {
        let headers = new Headers();
        let token = localStorage.getItem('feathers-jwt');

        headers.append('Content-Type', 'application/json');
        headers.append('Authorization', 'Bearer ' + token)
        return this.http.post(AppSettings.API_ENDPOINT + '/organization', organization, { headers: headers }).map(res => res.json())
    }

    delete(id) {
        let headers = new Headers();
        let token = localStorage.getItem('feathers-jwt');

        headers.append('Content-Type', 'application/json');
        headers.append('Authorization', 'Bearer ' + token)
        return this.http.delete(AppSettings.API_ENDPOINT + '/organization?id=' + id, { headers: headers }).map(res => res.json())
    }

    edit(id, organization) {
        let headers = new Headers();
        let token = localStorage.getItem('feathers-jwt');

        headers.append('Content-Type', 'application/json');
        headers.append('Authorization', 'Bearer ' + token)
        return this.http.patch(AppSettings.API_ENDPOINT + '/organization?id=' + id, organization, { headers: headers }).map(res => res.json())
    }
}

组件 ngoni(我加载组织的地方)

  ngOnInit() {

     this.currentUser = JSON.parse(localStorage.getItem('user'));
    if(this.currentUser.roleId == '2') {
      this.isAdmin = true; //check if user is admin
  }
        if(JSON.parse(localStorage.getItem('user')).roleId == '2') {
            this.isAdmin = true; //check if user is admin
        }
        this.organizacijeService.currentData.subscribe(res => {

                this.loadOrgs();

        })



    }

    loadOrgs() {
        this.organizacijeService.getAll().subscribe(res => {
            this.organizations[0].array = res.data;
            console.log(this.organizations[0])
        }, err => {
            this.toast.error('Organization: ' + JSON.parse(err._body).message, 'Failed')
        })
    }

【问题讨论】:

  • 如果我手动转到我的 localhost:3000/organization 并写入 localhost:3000/organization?$limit=20&$skip=20 我可以显示其他数据块,因此它们存在API。现在我如何编辑我的分页和我的服务以检索其他块并相应地对它们进行分页。

标签: node.js angular express angular5 feathersjs


【解决方案1】:

您可以通过以 50 为增量增加 $skip query parameter 直到 page.total - 50 来加载后续页面。

我会记住,一次显示 10 万条记录可能仍会导致前端出现性能问题。

【讨论】:

  • 感谢您抽出宝贵时间。我是否会在使用 forloop 的不同 getall2 函数中编写跳过参数,以便在单击页面/按钮时增加 50,然后以某种方式将两个结果附加到一个数组中,还是?再次感谢
  • 它只会从请求中返回数据。您必须自己维护并附加到全局数组。
  • 我所做的是在页面加载时发送请求,查询设置为限制 50,并跳过 0。更改分页以执行查询,在每个页面上添加 +50 跳过,并使用分页上的总项目来计算 res 。全部的。一切正常。非常感谢您的帮助!
【解决方案2】:

您可以在禁用分页的服务器端使用代理服务:

app.use('organizations-unpaginated', {
  find(params){
    const _params = Object.assign({}, params, { paginate: false });
    return app.service('organizations').find(_params);
  }
})

正如 Daff 所说,您会遇到性能问题,我通常会说渲染 100k DOM 元素(几乎所有这些元素都是不可见的)是不好的做法。

【讨论】:

  • 感谢您抽出宝贵时间阅读并分享您的想法!我能够让它工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-27
  • 1970-01-01
  • 2016-08-29
  • 2021-12-15
  • 1970-01-01
  • 2016-02-27
  • 2019-11-12
相关资源
最近更新 更多