我正在使用JSON响应的Node.js服务器。我有一个包含数据的旧服务器。 Node.js服务器充当将用户连接到数据的中间人。旧服务器将数据作为csv返回,其中列为键,行为对象。我想把它变成一个json对象数组。我正在使用此工具执行此操作:https://github.com/Keyang/node-csvtojson。我可以让工具为我构造输出,或者我可以有一个函数调用,每行传入并自己构造它。我目前正在做晚些时候。
我的应用程序的用户可以传入搜索值,这意味着只应返回包含此值的行。用户还可以传入过滤器键和值,这意味着只有键包含每个键值的行,并且应返回给定的值。它们当然可以同时提供搜索和过滤值,或者两者都不提供。它们还提供了一个排序键,它是对象排序数组的关键。他们还给我一个排序顺序:升序或降序。他们还给我一个页面大小和偏移量,以便返回,这是为了分页。
我的问题是,使用可能包含数百万行的数据集处理此问题的最佳方法是什么?我无法修改旧版服务器。这就是我所拥有的。它有效,但我想尽可能地提高性能。有没有更有效的方法来进行排序,搜索,过滤,分页等?添加到数组然后排序而不是使用二进制搜索树并在添加期间排序会更好吗?有没有办法可以使用流来提高性能?我希望服务器受CPU性能而不是RAM的限制。我正在寻找任何推荐以获得更好的性能。谢谢! :)
编辑:此外,以下代码的哪一部分是阻止?
function searchRow(row, search) {
if (search) {
for (var key in row) {
if (row.hasOwnProperty(key) && row[key].toString().toLowerCase().indexOf(search.toLowerCase()) > -1) {
return true;
}
}
return false;
} else {
return true;
}
}
function filterByField(obj) {
return obj.field === this.valueOf();
}
function filterRow(row, filter) {
if (filter) {
filter = JSON.parse(decodeURIComponent(filter));
var passed = true;
for (var key in filter) {
if (filter.hasOwnProperty(key)) {
var index = row[key].toString().toLowerCase().indexOf(filter[key].toString().toLowerCase());
passed = passed && (index > -1);
}
if (!passed) {
break;
}
}
return passed;
} else {
return true;
}
}
function orderByKey(key, reverse, a, b) {
return function (a, b) {
var x = (a[key] || '').toString().toLowerCase();
var y = (b[key] || '').toString().toLowerCase();
if (x > y) {
return reverse ? -1 : 1;
} else if (y > x) {
return reverse ? 1 : -1;
} else if (hash(a) > hash(b)) {
return reverse ? -1 : 1;
} else if (hash(b) > hash(a)) {
return reverse ? 1 : -1;
} else {
return 0;
}
};
}
function sortedInsert(element, array, key, reverse) {
array.splice(locationOf(element, array, key, reverse) + 1, 0, element);
return array;
}
function locationOf(element, array, key, reverse, start, end) {
if (array.length === 0) {
return -1;
}
start = start || 0;
end = end || array.length;
var pivot = parseInt(start + (end - start) / 2, 10);
var c = orderByKey(key, reverse, element, array[pivot]);
if (end - start <= 1) {
return c == -1 ? pivot - 1 : pivot;
}
switch (c) {
case -1: return locationOf(element, array, key, reverse, start, pivot);
case 0: return pivot;
case 1: return locationOf(element, array, key, reverse, pivot, end);
}
}
function getTable(path, columns, delimiter, query) {
var deferred = q.defer();
var headers = [];
var data = [];
delimiter = delimiter ? delimiter : '\t';
var converter = new Converter({
delimiter: delimiter,
noheader: true,
headers: columns,
workerNum: os.cpus().length,
constructResult: false
});
converter.on("error", function(errMsg, errData) {
deferred.reject(errMsg);
});
converter.on("record_parsed", function(row) {
if (searchRow(row, query.search) && filterRow(row, query.filter)) {
sortedInsert(row, data, query.sort || headers[0].split("!").pop(), query.order === 'desc');
}
});
converter.on("end_parsed", function() {
var offset = parseInt(query.offset || 0);
var limit = parseInt(query.limit || data.length);
var total = data.length;
data = data.slice(offset, offset + limit);
deferred.resolve({
"total": total,
"rows": data
});
});
var options = {
url: config.url + path,
gzip: true,
method: 'GET'
};
request(options, function (error, response, body) {
if (error || response.statusCode != 200) {
deferred.reject(error);
}
}).pipe(converter);
return deferred.promise;
}