Datatables结合Node.js、Elasticsearch实现时服务器端分页失效问题
问题原因
- 响应字段错误:返回给Datatables的
data字段是全量ES查询结果,没有做分页切片,导致所有数据都被渲染到同一页 - 参数类型不符合规范:
recordsFiltered要求是数字类型,代表过滤后的总记录数,原有代码中将其赋值为切片后的数组,不符合Datatables服务端模式的响应规则 - 缺少分页偏移参数:服务端模式下Datatables会传递
start参数代表当前页的起始索引,原有代码只获取了每页条数length,没有按偏移量截取对应页的数据
修复代码
1. 修复Controller逻辑(临时解决方案,适合数据量小于1万的场景)
var elasticDataModel = require('../model/getDataElastic'); exports.getData = function (req, res) { elasticDataModel(function (elasticList) { const draw = parseInt(req.body.draw) // 读取Datatables传递的分页参数 const start = parseInt(req.body.start) || 0 const pageSize = parseInt(req.body.length) || 20 // 无搜索逻辑时过滤后总条数等于总记录数 const recordsTotal = elasticList.length const recordsFiltered = elasticList.length // 截取当前页对应的数据 const pageData = elasticList.slice(start, start + pageSize) const data = JSON.stringify({ "data": pageData, "draw": draw, "recordsTotal": recordsTotal, "recordsFiltered": recordsFiltered }); res.send(data); }); }
2. 全量优化方案(适合数据量大于1万的场景,直接从ES做分页查询减少内存占用)
首先修改Model层,支持接收分页参数:
const { Client } = require('@elastic/elasticsearch') const client = new Client({ node: '', auth: { username: '', password: '' } }) // 新增from、size参数接收分页条件,同时返回总记录数 module.exports = function getElasticData(callback, from = 0, size = 20) { client.search({ index: 'anomalies02_bhc-lstm2', from: from, size: size, body: { query: { match_all: {} } } }, function (error, response, status) { if (error) { console.log("search error: " + error) return callback([], 0) } if (response) { const elasticList = response.body.hits.hits.map(hit => hit) // 同时返回当前页数据和总条数 callback(elasticList, response.body.hits.total.value); } else { console.log("<p>No results</p>"); callback([], 0) } }); }
再修改对应的Controller逻辑:
var elasticDataModel = require('../model/getDataElastic'); exports.getData = function (req, res) { const draw = parseInt(req.body.draw) const start = parseInt(req.body.start) || 0 const pageSize = parseInt(req.body.length) || 20 // 直接将分页参数传给ES,查询对应页的数据 elasticDataModel(function (pageData, total) { const recordsTotal = total const recordsFiltered = total const data = JSON.stringify({ "data": pageData, "draw": draw, "recordsTotal": recordsTotal, "recordsFiltered": recordsFiltered }); res.send(data); }, start, pageSize) }
内容的提问来源于stack exchange,提问作者GhostyIs1337
相关产品推荐
相关产品推荐

