Как я должен представлять табличные данные в JSON?
Я пишу API для извлечения данных из JSBC-подключенного Java-сервлета через JSON. Я решил использовать JSON, потому что мы захотим делать сортировки и другие операции с данными в браузере, и мы будем получать доступ к данным из разных доменов.
Поскольку я выполняю SQL-запросы в JavaScript, возвращаемые данные носят табличный характер. Я начал писать так, чтобы вы вернули список меток столбцов, а затем массивы значений, например:
{
"columns": [
"given_name",
"surname",
],
"results": [
[
"Joe",
"Schmoe"
],
[
"Jane",
"Doe"
]
]
}
Но когда я начинаю писать JavaScript для обработки возвращаемых данных, мне интересно, лучше ли просто выводить результаты с помощью пар ключ/значение, например:
{
"results": [
{
"given_name": "Joe",
"surname": "Schmoe"
},
{
"given_name": "Jane",
"surname" : "Doe"
}
]
}
Если вы возвращаете много результатов, много повторяющегося текста. Но мы собираемся транспортировать gzipped, поэтому я не слишком обеспокоен пропускной способностью.
В принципе, должен ли я это сделать, чтобы получить доступ к моим данным с помощью
$.getJSON(query, function(data) {
var columns = data.columns;
var results = data.results;
$.each(results, function(key, row) {
console.log(row[columns.indexOf('surname')]);
});
});
или гораздо красивее
$.getJSON(query, function(data) {
var results = data.results;
$.each(results, function(key, row) {
console.log(row.surname);
});
});
?
По сути, я хочу знать, может ли потенциальный удар по производительности оправдывать более чистый синтаксис последнего варианта.
Последующие действия
Я реализовал его в обоих направлениях и в профиле. Профилирование было отличной идеей! Различия в производительности были незначительными. Различия в размере передачи данных были существенными, но с сжатием Gzip разница составляла до 5-6% между обоими форматами и между очень большими и очень маленькими наборами данных. Поэтому я собираюсь с более красивой реализацией. Для этого конкретного приложения я могу ожидать, что все клиенты будут поддерживать Gzip/Deflate, поэтому размер не имеет значения, а вычислительная сложность как для клиента, так и для сервера аналогична достаточно, чтобы это не имело значения.
Для всех, кто интересуется, вот мои данные с графиками!
Ответы
Ответ 1
Синтезируя другие ответы:
- Формат вашего провода не должен быть таким же, как ваш формат в памяти.
- Профиль, который лучше - см., если это имеет значение.
- Упрощение обычно лучше начинать с.
Далее:
- Если у вас есть только страница результатов и несколько пользователей, то второй формат может быть не хуже 1-го формата.
- Если ваши данные довольно разреженные, второй вариант может быть лучше.
- Если вы отправляете 1000 или строк данных, и у вас есть миллионы пользователей, тогда возможно, что размер отправляемых вами данных может начать иметь значение, и, возможно, может помочь 1-й формат.
- Вы не можете гарантировать, что все пользовательские агенты поддерживают gzip/deflate, поэтому имейте это в виду.
Ответ 2
Профиль обоим. Оптимизируйте впоследствии.
Ответ 3
Вам не нужно привязывать код к более компактному, но также более громоздкому формату. Просто напишите простой JS-адаптер, чтобы проверить возвращенную структуру на наличие columns
. Если это отсутствует, вы имеете дело с простым массивом объектов. Если он присутствует, вы можете легко сопоставить громоздкий формат с более удобным форматом.
Ответ 4
FWIW Я бы выбрал второй вариант, он поддается более чистому JavaScript, как вы заметили, а также будет проще для человека читать и понимать. Мне кажется, что читаемость превосходит любую небольшую выгоду, которую вы получаете от варианта 1.
Я также предполагаю, что если вы когда-нибудь добавите больше столбцов или порядок столбцов, с первым вариантом, вам, вероятно, придется переписать много JavaScript, так как вы будете работать с позицией данных в ответе.
Ответ 5
Еще одна структура JSON, из которой я получил очень хорошие результаты:
{
"recordCount": 2,
"data": {
"Id": [1, 2],
"Title": ["First record", "Second record"]
"Value": [18192, 18176]
}
}
Перемещение всех данных:
for (var i = 0; i < recordSet.recordCount; ++i) {
console.log("Record " + i.toString() + ":");
for (var field in recordSet.data)
console.log("\t" + field + ": " + recordSet.data[field][i].toString());
}