JSON
JSON (JavaScript Object Notation) — простой формат обмена данными, удобный для чтения и написания как человеком, так и компьютером. Он основан на подмножестве языка программирования JavaScript, определенного в стандарте ECMA-262 3rd Edition — December 1999. JSON — текстовый формат, полностью независимый от языка реализации, но он использует соглашения, знакомые программистам C-подобных языков, таких как C, C++, C#, Java, JavaScript, Perl, Python и многих других. Эти свойства делают JSON идеальным языком обмена данными.
JSON основан на двух структурах данных:
- Коллекция пар ключ/значение. В разных языках, эта концепция реализована как объект, запись, структура, словарь, хэш, именованный список или ассоциативный массив.
- Упорядоченный список значений. В большинстве языков это реализовано как массив, вектор, список или последовательность.
Это универсальные структуры данных. Почти все современные языки программирования поддерживают их в какой-либо форме. Логично предположить, что формат данных, независимый от языка программирования, должен быть основан на этих структурах.
В нотации JSON это выглядит так:
Объект — неупорядоченный набор пар ключ/значение. Объект начинается с {открывающей фигурной скобки и заканчивается }закрывающей фигурной скобкой. Каждое имя сопровождается :двоеточием, пары ключ/значение разделяются ,запятой.
Массив — упорядоченная коллекция значений. Массив начинается с [открывающей квадратной скобки и заканчивается ]закрывающей квадратной скобкой
Значение может быть строкой в двойных кавычках, числом, true, false, null, объектом или массивом. Эти структуры могут быть вложенными.
Строка — коллекция нуля или больше символов Unicode, заключенная в двойные кавычки, используя \обратную косую черту в качестве символа экранирования. Символ представляется как односимвольная строка. Похожий синтаксис используется в C и Java.
Число представляется так же, как в C или Java, кроме того, что используется толко десятичная система счисления.
Пробелы могут использоваться между любыми лексемами.
Исключая некоторые детали кодирования, вышеизложенное полностью описывает язык.
www.json.org
Технологический блог фирмы 1С | 1С:Зазеркалье
12.12.2019 Интеграция мобильной платформы со средствами статистики
Сделать удобное мобильное приложение – дело непростое, это редко получается с первого раза. Для разработчика важно понять, насколько мобильное приложение удобно в использовании, где пользователь встречается с трудностями, использует ли пользователь мобильное приложение так, как задумал разработчик.
Чтобы решить эту задачу, мобильные приложения интегрируются с сервисами аналитики; сервисы помогают собрать информацию о статистике использования приложения, о действиях пользователей, источниках установок приложения и т.д.
02.12.2019 Развитие Системы взаимодействия
Мы продолжаем развивать Систему взаимодействия в соответствии с нашим видением перспектив продукта и с учетом замечаний пользователей.
Рассказать друзьям:20.11.2019 Повышение удобства установки расширений в браузерах при работе с веб-клиентом
Для полноценной работы веб-клиента 1С иногда может потребоваться установить дополнительные программы: расширение для браузера и/или расширения для работы с файлами, криптографией, программой «1С:Предприятие – оповещения и запуск», внешние компоненты. Механизмы безопасности браузеров не дают сделать это полностью автоматически и требуют участия пользователя на некоторых фазах установки; в некоторых случаях может потребоваться перезапуск браузера.
В версии 8.3.17 мы переработаем интерфейс установки расширений, сделаем его более удобным для пользователей.
Рассказать друзьям:11.11.2019 Изменения в функциональности демонстрации экрана в Системе взаимодействия
В версии 8.3.17 в функциональности демонстрации экрана в Системе взаимодействия (появилась в версии 8.3.16) произойдут изменения:
В версии 8.3.16 в Chrome демонстрация экрана
- Была доступна, начиная с версии Chrome 56
- Требовала установленного браузерного расширения
- Позволяла демонстрировать:
- Весь экран
- Вкладку Chrome
В версии 8.3.17 в Chrome демонстрация экрана
- Доступна, начиная с версии Chrome 72
- Не требует установленного браузерного расширения
- Позволяет демонстрировать:
- Весь экран
Окна программ- Вкладку Chrome
28.10.2019 Параметр командной строки /Out на Windows будет выводить данные в Unicode-файл
В версии 8.3.18 планируется следующее изменение: параметр командной строки /Out на ОС Windows будет выводить данные в файл в кодировке UTF-8 (поведение параметра будет унифицировано для всех поддерживаемых ОС).
Рассказать друзьям:11.10.2019 Новое сочетание клавиш для команды «Искать везде»
Команда «Искать везде» используется для глобального поиска выделенного текста в поле ввода, в текстовом и форматированном документе, а также используется для поиска значения текущей ячейки в таблице или табличном документе.
Это вызвано тем, что в типовых конфигурациях сочетание клавиш Ctrl+Shift+C используется для копирования в буфер обмена выделенных строк в таблице. Рассказать друзьям:
04.10.2019 Ряд параметров контроля объема памяти процессов можно будет делать с лицензией ПРОФ
Нами принято решение, что изменение значений параметров:
- Критический объем памяти процессов
- Временно допустимый объем памяти процессов
- Предел превышения (секунд) временно допустимого объема памяти процессов
При этом поведение для опции «Временно допустимый объем памяти процессов» для ПРОФ и КОРП лицензий будет отличаться.
С лицензиями ПРОФ изменение параметра будет действовать только на перезапуск процессов, а с лицензиями КОРП – и на перезапуск процессов, и на прерывание объёмных клиентских вызовов сервера.
Сейчас в версии 8.3.15 эти опции доступны только с лицензиями уровня КОРП.
Изменение попадет в следующую финальную версию 8.3.15 (после 8.3.15.1656).
23.08.2019 Программное наполнение командами контекстного меню планировщика
В версии 8.3.16 появится функциональность, позволяющая программно наполнять контекстное меню планировщика, передавая при этом информацию об области, на которой был произведен клик, будь то элемент, заголовок измерения, пустая область элементов и т.п. Это позволит разработчику конфигурации более гибко настраивать содержимое контекстного меню в зависимости от того, на чем был произведен клик. Появится также возможность задавать действие по умолчанию при нажатии левой кнопкой мыши в зависимости от области нажатия.
Рассказать друзьям: 19.07.2019
Поддержка Chrome и Firefox на macOS в 8.3.16
Начиная с версии 8.3.16 веб-клиент 1С станет поддерживать браузеры Chrome и Firefox на macOS. Минимальная поддерживаемая версия Chrome поднята до 49.
Рассказать друзьям:v8.1c.ru
Меняем опыт просмотра JSON в браузере / Habr
Сегодня я хочу рассказать о JsonDiscovery, браузерном расширении для просмотра JSON. Возможно вы скажете: «у нас и так полно подобных расширений!». Да, полно, но фичи JsonDiscovery отличают его от других и делают его действительно мощным.
Давайте же взглянем поближе…
Для демонстраций я использовал JSON-файл коллекции всех карт из проекта Hearthstone-DB (спасибо Ольге Кобец за идею). И вот как он выглядит, если открыть его в браузере с установленным JsonDiscovery:
На первый взгляд это всего лишь еще один раскрасчик JSON. Все потому, что большинство фич не на поверхности, чтобы не отвлекать вас от вашего JSON. Давайте их раскроем:
- Простое копирование фрагментов JSON в буфер
- Сигнатура структуры JSON
- Трансформация JSON с помощью запроса
- Подсказки при написании запроса к JSON
- Настройка отображения данных из JSON
- Шаринг «отчетов» по ссылке
Рассмотрим каждый пункт детальнее.
Простое копирование фрагментов JSON в буфер
Бывает что нужно скопировать фрагмент JSON’а, то есть некоторого вложенного объекта или массива. С JsonDiscovery это простая задача, так как каждый развернутый объект и массив имеют кнопки действий. Одна из них кнопка «ƒ» button, нажав которую можно скопировать JSON в компактном или форматированном виде:
Сигнатура структуры JSON
Когда вы изучаете данные, полезно иметь представление об их структуре. Просто наведите на кнопку «S» в панели действий на развернутом объекте или массиве и вы увидите сигнатуру структуры поддерева, как примерно это выглядит в TypeScript:
Вы так же можете навести на свойство или тип значения в сигнатуре структуры чтобы получить некоторые детали, например о том какие значения использовались для поля:
Запросы к JSON
Клик по кнопке «Make report» переводит вас на страницу, где вы можете делать запросы к вашему JSON и/или настраивать его отображение:
Для запросов используется язык Jora. Он частично основывается на синтаксисе JavaScript 2015+, но в большей степени, задуман быть компактным и выражать больше (в рамках задачи запроса к данным).
Обычно вам нужно только выбрать некоторое подмножество данных используя некоторый путь, вроде foo.bar.baz
. Если ключ имеет запрещенные символы просто используйте []
(квадратные скобки), то есть foo['a key with whitespaces']
. Все как в JavaScript, за исключением того, что не нужно переживать существует путь или нет:
Часто необходимо использовать фильтрацию или мапинг. Jora предоставляет .[]
для фильтрации и .()
для мапинга:
Пример на скриншоте выше (cards.[health].({ name, health })
) можно записать на JavaScript так:
cards.filter($ => $.health).map($ => ({ name: $.name, health: $.health }))
Что гораздо многословнее, не так ли?
Вы можете найти больше о самом Jora и его синтаксисе в его репозитории на github. (Кстати, у него так же есть CLI и песочница)
Подсказки при написании запроса к JSON
Эту фичу невозможно описать правильно. Это нужно попробовать самому. Хотя бы раз:
Настройка отображения данных
Когда вы выбрали необходимые данные из JSON, вы можете настроить их отображение. Например, вывести их таблицей, или списком, вроде такого:
К сожалению, на данный момент нет достаточной документации о том, как описывать отображение (все что можно найти, может быть найдено в репозитории discovery.js). Но я верю это исправится в ближайшем будущем.
Шаринг «отчетов» по ссылке
Это были наиболее впечатляющие фичи JsonDiscovery, но есть гораздо больше фич поменьше, потому что расширение и проекты, лежащие в его основе, создаются с вниманием к деталям. И я могу с уверенностью сказать, все это меняет опыт работы с JSON в браузере!
JsonDiscovery доступен как расширение к Chrome и Firefox, и разрабатывается exdis как проект с открытым исходным кодом. Расширение построено на основе проекта Discovery.js, который еще на раней стадии разработки, но уже полезен для проектов вроде JsonDiscovery. Так что ожидается больше улучшений и фич в будущем. Следите за анонсами!
habr.com
Правильный JSON API или JSON RPC / Habr
Что же такое JSON API ?
JSON — Текстовый формат обмена данными JSON
API — Программный интерфейс приложения API
Ключевые слова здесь: интерфейс обмена данными.
A, что же тогда JSON-RPC?
JSON — мы уже в курсе.
RPC — удаленный вызов процедур RPC
Приходим к выводу, что JSON-RPC это: удаленный обмен данными.
Наверняка этот обмен данными будет происходить с неким интерфейсом, т.е. с API.
И в чем проблема?! Спросите Вы. А в том, что некоторые программисты разрабатывая JSON API, т.е интерфейс, забывают про JSON-RPC.И начинается очередное изобретение велосипеда. Frontend программист говорит: «я передам тебе такой то json», а Backend программист отвечает: «а я тебе верну такой то json». И все бы ничего, но было бы хорошо вспомнить о том, что умные люди уже давно разработали стандарты, вернее протоколы обмена данными. И не какие то сверх сложные, а очень даже простые: JSON-RPC
Вероятно многие, если не сказать, что почти все, знают и даже пользуются этими протоколами. Написана куча серверов и т.д. Но вот лично меня не все устроило в существующих протоколах. Они показались мне не достаточно гибкими и не во всем логичными. Как вы уже догадались решил я изобрести свой велосипед json-rpc-1.5
Главные отличия от существующих протоколов это:
- Опциональный параметр «sign» — Signature (подпись) или Token
- В запросах вместо параметра «param» используется параметр «data», т.к. мы всегда отправляем данные, а не просто параметры.
- Во всех ответах всегда возвращается параметр «result» и в нем находится описание результата запроса «success» или «error».
- Все данные в ответах приходят в параметре «data»
- Можно использовать алиасы для названия параметров запроса и ответа
Может показаться. что отличия незначительные, но они принципиально важные.
Кстати, данный протокол появился на практике, т.е. создавая json api я использовал подход описанный в этом протоколе.
PS:
Получив кучу отрицательных комментариев и минусов, решил еще раз проверить, может я действительно, что то не так делаю? Естественно, всё что я здесь пишу, это мое личное мнение и я никому ничего не навязываю. Приведу пару примеров:
1. Пример запроса JSON API Yandex директ:
{
"method": "GetClientInfo",
"param": ["agrom"],
"locale": "ru",
"token": "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"
}
У них же можно почитать и про токены: Авторизационные токены
2. Пример из Сбербанк API Оплата из мобильного приложения с использованием Apple Pay
JSON запрос приводить не буду, он большой, по ссылке можно посмотреть.
Важно, что JSON запрос содержит «paymentToken». Вот ссылка на требования к формированию токена от Apple
Важно понимать, что токены и подписи в API используются часто, естественно на ряду с другими методами защиты. И те кто работает с разного рода API, прекрасно это знают.
habr.com
Объединение нескольких запросов в один вызов HTTP с помощью пакетной обработки JSON — Microsoft Graph
- Время чтения: 3 мин
В этой статье
Пакетная обработка JSON позволяет оптимизировать приложение, объединив несколько запросов в один объект JSON. Например, клиент может создать представление из таких несвязанных данных:JSON batching allows you to optimize your application by combining multiple requests into a single JSON object. For example, a client might want to compose a view of unrelated data such as:
- Изображение, хранящееся в OneDriveAn image stored in OneDrive
- Список задач ПланировщикаA list of Planner tasks
- Календарь группыThe calendar for a group
Объединение трех этих запросов в один может значительно снизить задержку в сети, ускорив работу приложения.Combining these three individual requests into a single batch request can save the application significant network latency.
Первый пакетный запрос JSONFirst JSON batch request
Сначала нужно создать пакетный запрос JSON для предыдущего примера. В этом сценарии отдельные запросы никак не зависят друг от друга, поэтому их можно поместить в пакетный запрос в любом порядке.First you construct the JSON batch request for the previous example. In this scenario, the individual requests are not interdependent in any way and therefore can be placed into the batch request in any order.
POST https://graph.microsoft.com/v1.0/$batch
Accept: application/json
Content-Type: application/json
{
"requests": [
{
"id": "1",
"method": "GET",
"url": "/me/drive/root:/{file}:/content"
},
{
"id": "2",
"method": "GET",
"url": "/me/planner/tasks"
},
{
"id": "3",
"method": "GET",
"url": "/groups/{id}/events"
},
{
"id": "4",
"url": "/me",
"method": "PATCH",
"body": {
"city" : "Redmond"
},
"headers": {
"Content-Type": "application/json"
}
}
]
}
Ответы на пакетные запросы могут отображаться в другом порядке. Для сопоставления отдельных запросов и ответов можно использовать свойство id
.Responses to the batched requests might appear in a different order. The id
property can be used to correlate individual requests and responses.
200 OK
Content-Type: application/json
{
"responses": [
{
"id": "1",
"status": 302,
"headers": {
"location": "https://b0mpua-by3301.files.1drv.com/y23vmagahszhxzlcvhasdhasghasodfi"
}
},
{
"id": "3",
"status": 401,
"body": {
"error": {
"code": "Forbidden",
"message": "..."
}
}
},
{
"id": "2",
"status": 200,
"body": {
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.plannerTask)",
"value": []
}
},
{
"id": "4",
"status": 204,
"body": null
}
]
}
Формат запросаRequest format
Пакетные запросы всегда отправляются с помощью метода POST
в конечную точку /$batch
.Batch requests are always sent using POST
to the /$batch
endpoint.
Текст пакетного запроса JSON состоит из одного объекта JSON с один обязательным свойством: requests
. Свойство requests
является массивом отдельных запросов. Для каждого отдельного запроса требуются свойства id
, method
и url
.A JSON batch request body consists of a single JSON object with one required property: requests
. The requests
property is an array of individual requests. For each individual request, the id
, method
, and url
properties are required.
Основная функция свойства id
— сопоставление отдельных запросов и ответов. Это позволяет серверу обрабатывать запросы пакета в наиболее эффективном порядке.The id
property functions primarily as a correlation value to associate individual responses with requests. This allows the server to process requests in the batch in the most efficient order.
Свойства method
и url
отображаются в начале любого HTTP-запроса. method — это метод HTTP, а URL — это URL-адрес ресурса, на который обычно отправляется отдельный запрос.The method
and url
properties are exactly what you would see at the start of any given HTTP request. The method is the HTTP method, and the URL is the resource URL the individual request would typically be sent to.
Отдельные запросы также могут содержать свойства headers
и body
.Individual requests can optionally also contain a headers
property and a body
property. Обычно это объекты JSON, как показано в предыдущем примере.Both of these properties are typically JSON objects, as shown in the previous example. В некоторых случаях body
может быть значением в кодировке URL Base64, а не объектом JSON (например, если body представляет собой изображение).In some cases, the body
might be a base64 URL-encoded value rather than a JSON object — for example, when the body is an image. Когда в запрос включено свойство body
, объект headers
должен содержать значение для свойства Content-Type
.When a body
is included with the request, the headers
object must contain a value for Content-Type
.
Формат ответаResponse format
Формат ответа для пакетных запросов JSON почти такой же, как формат запроса. Ниже приведены основные различия.The response format for JSON batch requests is similar to the request format. The following are the key differences:
- Свойство в основном объекте JSON называется
responses
, а неrequests
.The property in the main JSON object is namedresponses
as opposed torequests
. - Порядок отображения ответов и запросов может отличаться.Individual responses might appear in a different order than the requests.
- Вместо свойств
method
иurl
отдельные ответы содержат свойствоstatus
. Значениеstatus
— это код состояния HTTP.Rather thanmethod
andurl
, individual responses have astatus
property. The value ofstatus
is a number that represents the HTTP status code.
Пакетный ответ обычно содержит код состояния 200
или 400
. Если пакетный запрос имеет неправильный формат, код состояния — 400
. Если пакетный запрос пригоден для анализа, код состояния — 200
. Код состояния 200
пакетного ответа не указывает на успешное выполнение отдельных запросов в пакете. Именно поэтому у каждого отдельного ответа в свойстве responses
есть код состояния.The status code on a batch response is typically 200
or 400
. If the batch request itself is malformed, the status code is 400
. If the batch request is parseable, the status code is 200
. A 200
status code on the batch response does not indicate that the individual requests inside the batch succeeded. This is why each individual response in the responses
property has a status code.
В дополнение к свойству responses
в пакетном ответе может быть свойство nextLink
. Это позволяет Microsoft Graph возвращать пакетный ответ сразу после выполнения каждого из отдельных запросов. Чтобы убедиться, что получены все отдельные ответы, продолжайте переходить по ссылке nextLink
, пока она передается.In addition to the responses
property, there might be a nextLink
property in the batch response. This allows Microsoft Graph to return a batch response as soon as any of the individual requests has completed. To ensure that all individual responses have been received, continue to follow the nextLink
as long as it exists.
Выстраивание последовательности запросов с помощью свойства dependsOnSequencing requests with the dependsOn property
С помощью свойства dependsOn
можно задать порядок выполнения запросов. Это свойство представляет собой массив строк, которые ссылаются на значения id
различных отдельных запросов. Поэтому значения id
должны быть уникальными. Например, в следующем запросе клиент указывает, что в первую очередь нужно выполнить запросы 1 и 3, затем запросы 2 и 4.Individual requests can be executed in a specified order by using the dependsOn
property. This property is an array of strings that reference the id
of a different individual request. For this reason, the values for id
must be unique. For example, in the following request, the client is specifying that requests 1 and 3 should be run first, then request 2, then request 4.
{
"requests": [
{
"id": "1",
"method": "GET",
"url": "..."
},
{
"id": "2",
"dependsOn": [ "1" ],
"method": "GET",
"url": "..."
},
{
"id": "3",
"method": "GET",
"url": "..."
},
{
"id": "4",
"dependsOn": [ "2" ],
"method": "GET",
"url": "..."
}
]
}
Если отдельный запрос не будет выполнен, то любой зависящий от него запрос также не будет выполнен с кодом состояния 424
(ошибка зависимости).If an individual request fails, any request that depends on that request fails with status code 424
(Failed Dependency).
Обход ограничения на длину URL-адреса с помощью пакетной обработкиBypassing URL length limitations with batching
Еще один вариант использования пакетной обработки JSON — обход ограничения на длину URL-адреса. Если предложение фильтра сложное, длина URL-адреса может превышать ограничения, встроенные в браузеры или другие HTTP-клиенты. Для выполнения таких запросов можно использовать пакетную обработку JSON, так как длинные URL-адреса просто станут частью полезных данных запроса.An additional use case for JSON batching is to bypass URL length limitations. In cases where the filter clause is complex, the URL length might surpass limitations built into browsers or other HTTP clients. You can use JSON batching as a workaround for running these requests because the lengthy URL simply becomes part of the request payload.
Известные проблемыKnown issues
Список текущих ограничений, связанных с пакетной обработкой, см. в разделе Известные проблемы.For a list of current limitations related to batching, see known issues.
См. такжеSee also
Дополнительные сведения о формате пакетных запросов и ответов JSON см. в спецификации формата JSON OData версии 4.01, раздел 18. Обратите внимание, что это рабочая версия спецификации, но внесение изменений не планируется.For more information about the JSON batch request/response format, see the OData JSON Format Version 4.01 specification, section 18. Note that this specification is currently in a draft version, but is not expected to change.
docs.microsoft.com
Работаем с JSON в SQL Server 2016 / Habr
JSON сейчас один из самых используемых форматов данных в разработке. Большинство современных сервисов возвращают информацию в виде JSON. JSON также предпочитаемый формат для хранения структурированный информации в файлах, например. Так как очень много данных используется в JSON-формате, то поддержка JSON в SQL Server особенно становится актуальной, чтобы иметь возможность обмениваться данными с другими сервисами.JSON стал одной из самых востребованных фич, добавленных в SQL Server 2016. Далее в статье мы рассмотрим основные механизмы работы с JSON.
Краткий обзор
Функции для работы с JSON в SQL Server позволяют анализировать и запрашивать данные JSON, преобразовывать JSON в реляционный вид и экспортировать результат SQL-запроса как JSON.
Если у вас есть JSON, вы можете достать оттуда данные или проверить их на валидность, используя встроенные функции JSON_VALUE, JSON_QUERY и ISJSON. Для изменения данных может быть использована функция JSON_MODIFY. Для более продвинутого использования функция OPENJSON позволяет преобразовывать массив JSON объектов в набор строк. Затем над этим набором можно выполнить любой SQL-запрос. Наконец, существует конструкция FOR JSON, которая преобразует результат запроса в JSON.
Посмотрим на несколько простых примеров. В следующем коде мы определим текстовую переменную, в которой будет JSON:
DECLARE @json NVARCHAR(4000)
SET @json =
N'{
"info":{
"type":1,
"address":{
"town":"Bristol",
"county":"Avon",
"country":"England"
},
"tags":["Sport", "Water polo"]
},
"type":"Basic"
}'
Теперь мы можем получить отдельные значения или объекты из JSON с помощью JSON_VALUE и JSON_QUERY:
SELECT
JSON_VALUE(@json, '$.type') as type,
JSON_VALUE(@json, '$.info.address.town') as town,
JSON_QUERY(@json, '$.info.tags') as tags
Этот запрос вернет «Basic», «Bristol» и [«Sport», «Water polo»]. Функция JSON_VALUE возвращает скалярное значение из JSON (то есть строку, число, булевское значение), которое расположено по «пути», указанному вторым параметром. JSON_QUERY возвращает объект или массив (в нашем примере это массив тегов) по «пути». Встроенные функции JSON используют похожий на JavaScript синтаксис для обращения к значениям и объектам в качестве второго параметра.
Функция OPENJSON позволяет обратиться к массиву внутри JSON и возвратить элементы этого массива:
SELECT value
FROM OPENJSON(@json, '$.info.tags')
В этом примере возвращаются строковые значения из массива тегов. Кроме того, OPENJSON может возвращать любой сложный объект.
Наконец, конструкция FOR JSON может отформатировать любой результат выполнения SQL-запроса в JSON:
SELECT object_id, name
FROM sys.tables
FOR JSON PATH
Рассмотрим эти функции подробнее.
Хранение данных JSON в SQL Server
В SQL Server JSON хранится как текст. Вы можете использовать тип NVARCHAR для этого. В следующем примере мы будем хранить JSON в поле InfoJson:
CREATE TABLE Person (
Id int IDENTITY PRIMARY KEY NONCLUSTERED,
FirstName nvarchar(100) NOT NULL,
LastName nvarchar(100) NOT NULL,
InfoJson nvarchar(max)
) WITH (MEMORY_OPTIMIZED=ON)
В SQL Server 2016 вы можете комбинировать обычные столбцы (FirstName и LastName в примере) и столбцы с JSON (InfoJSON в примере) в одной таблице. Также вы можете комбинировать столбцы JSON со столбцами с пространственными данными (spatial columns) и XML. В отличие от только реляционных или только документоориентированных хранилищ, вы можете выбирать принципы хранения для достижения большей гибкости в разработке.
Хотя JSON хранится в текстовых столбцах, это не просто обычный текст. В SQL Server есть механизм для оптимизации хранения текстовых столбцов с использованием различных механизмов сжатия, таких как сжатие UNICODE, которые позволяют экономить до 50% размера. Также вы можете хранить JSON в таблицах с columnstore индексами или сжимать их явно с использованием встроенный функции COMPRESS, которая использует алгоритм GZip.
JSON полностью совместим с любым компонентом SQL Server, который работает с типом NVARCHAR. В примере выше, JSON хранится в OLTP (Hekaton) таблице в памяти, которая предлагает суперпроизводительность. Вы можете хранить JSON в обычных таблицах, использовать columnstore индексы или FILESTREAM. Вы также можете загружать его из Hadoop используя таблицы Polybase, считывать из файловой системы, работать с ним в Azure SQL, использовать репликацию и т.д. Если вы скомбинируете таблицы, в которых хранится JSON с другими фичами SQL Server, такими как безопасность временных таблиц или безопасность на уровне строк, вы можете обнаружить мощные возможности, которые недоступны в существующих документоориентированных СУБД.
Если вы хотите обеспечить валидность хранимого JSON, вы можете добавить проверку на валидность с помощью ограничения и функции ISJSON:
ALTER TABLE Person
ADD CONSTRAINT [Content should be formatted as JSON]
CHECK ( ISJSON( InfoJSON )> 0 )
Во время выполнения ваши запросы не будут работать, если JSON отформатирован неправильно.
Т.к. JSON представлен в виде текста, нет необходимости менять что-то в ваших приложениях. Вы можете работать с JSON как с обычными строками. JSON может быть загружен с помощью ORM как строка и отправлен в клиентское JavaScript-приложение. Любые утилиты извлечения данных также будут работать.
Встроенные функции для обработки JSON
SQL Server 2016 предлагает несколько функций для обработки JSON:
- ISJSON( jsonText ) проверяет валидность JSON на соответствие спецификации. С помощью этой функции вы можете накладывать ограничения на столбцы, содержащие JSON
- JSON_VALUE( jsonText, path ) разбирает jsonText и выделяет отдельные значения по определенному «пути» (см. примеры ниже)
- JSON_QUERY( jsonText, path ) разбирает jsonText и выделяет объекты или массивы по определенному «пути» (см. примеры ниже)
- JSON_MODIFY( jsonText, path, newValue) изменяет значение какого-либо свойства по определенному «пути (см, примеры ниже)
Эти функции используют „пути“ в JSON для обращения к значениям или объектам. Примеры:
'$' // ссылается на весь объект JSON в исходном тексте
'$.property1' // ссылается на property1 в объекте JSON
'$[4]' // ссылается на 5-й элемент в массиве (индексы начинаются с 0)
'$.property1.property2.array1[5].property3.array2[15].property4' // ссылается на вложенное свойство
'$.info."first name"' // ссылается на свойство "first name" в объекте. Если название свойства содержит спецсимволы (пробелы, знак доллар и т.д.), то его нужно заключить в двойные кавычки
При использовании функции JSON_MODIFY в параметре path могут быть использованы дополнительные модификаторы. В общем случае синтаксис „пути“ выглядит как:
[append] [ lax | strict ] $.json_path
При указании модификатора append новое значение будет добавлено к массиву, на который ссылается json_path. Модификатор lax устанавливает режим работы, при котором неважно, существует свойство или нет. Если его нет, то будет добавлено. При использовании strict, если свойства нет, будет сгенерирована ошибка.
Знак доллара ($) ссылается на весь объект JSON (аналогично корневому узлу „/“ в XPath). Вы можете добавлять любое свойство после „$“ для обращения к элементам объекта. Рассмотрим простой пример:
SELECT Id, FirstName, LastName,
JSON_VALUE(InfoJSON, '$.info."social security number"') as SSN,
JSON_QUERY(InfoJSON, '$.skills') as Skills
FROM Person AS t
WHERE ISJSON( InfoJSON ) > 0
AND JSON_VALUE(InfoJSON, '$.Type') = 'Student'
Этот запрос возвращает имя и фамилию из обычных столбцов, социальный номер и массив навыков из JSON столбца. Результаты фильтруются по условию, при котором столбец InfoJSON должен содержать валидный JSON и значение Type в JSON столбце равно „Student“. Как вы уже поняли, вы можете использовать значения из JSON в любой части запроса (сортировка, группировка и т.п.).
Преобразование JSON в реляционный вид – OPENJSON
Функция OPENJSON возвращает таблицу, которая определяет массив объектов, проиводит итерацию по массиву и выводит каждый элемент массива в строке.
Пример
Данные на входе (JSON):
{
"Orders":
[
{
"Order": {
"Number": "S043659",
"Date": "2011-05-31T00:00:00"
},
"Account": "Microsoft",
"Item": {
"Price": 59.99,
"Quantity": 1
}
},
{
"Order": {
"Number": "S043661",
"Date": "2011-06-01T00:00:00"
},
"Account": "Nokia",
"Item": {
"Price": 24.99,
"Quantity": 3
}
}
]
}
SQL-запрос:
SELECT *
FROM OPENJSON(@json, N'$.Orders')
WITH (
Number VARCHAR(200) N'$.Order.Number',
Date DATETIME N'$.Order.Date',
Customer VARCHAR(200) N'$.Account',
Quantity INT N'$.Item.Quantity'
)
Результат
| Number | Date | Customer | Quantity ---------------------------------------------------------- | S043659 | 2011-05-31 00:00:00.000 | Microsoft | 1 | S043661 | 2011-06-01 00:00:00.000 | Nokia | 3
В примере выше мы определили, где будем искать массив JSON, который обрабатываем (т.е. по пути $.Orders), какие столбцы возвращаем и где в объектах JSON находятся значения, которые мы возвращаем как ячейки.
OPENJSON может быть использован в любом запросе при работе с данными. Как в примере, мы можем преобразовать массив JSON из переменной orders в набор строк и затем вставить их в обычную таблицу:
INSERT INTO Orders(Number, Date, Customer, Quantity)
SELECT Number, Date, Customer, Quantity
OPENJSON (@orders)
WITH (
Number varchar(200),
Date datetime,
Customer varchar(200),
Quantity int
) AS OrdersArray
4 столбца возвращаемого OPENJSON набора данных определены с помощью конструкции WITH. OPENJSON попытается найти свойства Number, Date, Customer и Quantity в каждом объекте JSON и преобразовать значения в столбцы в результирующем наборе данных. По умолчанию, если свойство не найдено, будет возвращен NULL. Предполагаем, что в переменной orders содержится следующий JSON:
'[
{"Number":1, "Date": "8/10/2012", "Customer": "Adventure works", "Quantity": 1200},
{"Number":4, "Date": "5/11/2012", "Customer": "Adventure works", "Quantity": 100},
{"Number":6, "Date": "1/3/2012", "Customer": "Adventure works", "Quantity": 250},
{"Number":8, "Date": "12/7/2012", "Customer": "Adventure works", "Quantity": 2200}
]'
Как видите, преобразование из JSON в реляционную форму очень простое. Все, что нужно, это определить имена столбцов и типы, а OPENJSON найдет свойства в JSON, которые соответствуют столбцам. В этом примере используется простой одноуровневый JSON, но OPENJSON может работать и со сложными вложенными объектами.
Также OPENJSON может быть использован, когда нужно скомбинировать реляционные данные и JSON в одном и том же запросе. Предположим, что массив JSON из предыдущего примера хранится в столбце OrdersJson. Следующий запрос вернет обычные и JSON поля:
SELECT Id, FirstName, LastName, Number, Date, Customer, Quantity
FROM Person
CROSS APPLY OPENJSON (OrdersJson)
WITH (
Number varchar(200),
Date datetime,
Customer varchar(200),
Quantity int ) AS OrdersArray
OPENJSON обработает массив в каждой ячейке и вернет одну строку для каждого объекта JSON в массиве. Синтаксис CROSS APPLY OPENJSON используется для объединения строк таблицы с данными JSON.
Индексирование данных JSON
Хотя значения в JSON хранятся как текст, вы можете индексировать их как обычные значения в столбцах. Можно использовать некластеризованные или полнотекстовые индексы.
Если нужно создать индекс на каком-либо свойстве JSON, которое часто используется в запросах, вы можете создать вычисляемый столбец, который ссылается на нужное свойство, затем создать обычный индекс по этому полю. В следующем примере мы оптимизируем запросы, которые фильтруют строки, используя свойство $.Company из столбца InfoJSON:
ALTER TABLE Person
ADD vCompany AS JSON_VALUE(InfoJSON, '$.Company')
CREATE INDEX idx_Person_1
ON Person(vCompany)
SQL Server предоставляет гибридную модель, в которой вы можете комбинировать обычные столбцы и значения из JSON в одном индексе.
Т.к. JSON это просто текст, можно использовать полнотекстовый индекс. Полнотекстовые индексы могут быть созданы на массиве значений. Вы создаете полнотекстовый индекс на столбце, который содержит массив JSON, или можете создать вычисляемый столбец, который ссылается на массив и добавить полнотекстовый индекс на этот столбец:
ALTER TABLE Person
ADD vEmailAddresses AS JSON_QUERY(InfoJSON, '$.Contact.Emails')
CREATE FULLTEXT INDEX ON Person(vEmailAddresses)
KEY INDEX PK_Person_ID ON jsonFullTextCatalog;
Полнотекстовый индекс полезен, если вам нужно оптимизировать запросы, которые ищут какое-либо значение в массиве JSON:
SELECT PersonID, FirstName,LastName,vEmailAddresses
FROM Person
WHERE CONTAINS(vEmailAddresses, '[email protected]')
Этот запрос вернет строки из Person, где массив электронных адресов содержит „[email protected]“. Полнотекстовый индекс не имеет специальных правил парсинга JSON. Он делит массив, используя разделители (двойные кавычки, запятые, квадратные скобки) и индексирует значения в массиве. Полнотекстовый индекс применим к массивам чисел или строк. Если у вас более сложные объекты в JSON, полнотекстовый индекс неприменим, так как он не сможет отличить ключи от значений.
В общем, одни и те же принципы создания индексов могут применяться к обычным столбцам или столбцам JSON.
Экспорт данных в JSON – FOR JSON
В SQL Server есть возможность преобразования реляционных данных в JSON с помощью конструкции FOR JSON. Если вам знакома конструкция FOR XML, то вы уже практически знаете и FOR JSON.
Пример
Исходные данные
| Number | Date | Customer | Price | Quantity | -------------------------------------------------------------------- | S043659 | 2011-05-31 00:00:00.000 | Microsoft | 59.99 | 1 | | S043661 | 2011-06-01 00:00:00.000 | Nokia | 24.99 | 3 |
SQL-запрос
SELECT Number AS [Order.Number], Date AS [Order.Date],
Customer AS [Account],
Price AS 'Item.UnitPrice', Quantity AS 'Item.Qty'
FROM SalesOrder
FOR JSON PATH, ROOT('Orders')
Результирующий JSON
{
"Orders": [
{
"Order": {
"Number": "S043659",
"Date": "2011-05-31T00:00:00"
},
"Account": "Microsoft",
"Item": {
"UnitPrice": 59.99,
"Qty": 1
}
},
{
"Order": {
"Number": "S043661",
"Date": "2011-06-01T00:00:00"
},
"Account": "Nokia",
"Item": {
"UnitPrice": 24.99,
"Qty": 3
}
}
]
}
Когда вы добавляете FOR JSON в конец SELECT запроса, SQL Server форматирует результат в виде JSON. Каждая строка будет представлена как один объект JSON, значения из ячеек будут значениями JSON, а названия столбцов будут использованы как ключи. Есть 2 типа конструкций FOR JSON:
- FOR JSON PATH позволяет определить структуру JSON на выходе, используя названия столбцов. Если вы используете разделенные точкой имена как синонимы столбцов, свойства JSON будут следовать соглашениям по именованию. Это похоже на FOR XML PATH где вы можете указать путь, разделенный слешами.
- FOR JSON AUTO автоматически создает вложенные массивы на базе иерархии таблиц в запросе. Похоже на FOR XML AUTO.
Заключение
JSON функции в SQL Server позволяют запрашивать и анализировать данные в виде JSON, а также преобразовывать их в реляционный вид и наоборот. Это позволяет интегрировать SQL Server во внешние системы, которые отдают или принимают JSON без дополнительных преобразований.
SQL Server также предлагает гибридную модель хранения, когда вы комбинируете реляционные данные и данные JSON в одной таблице. Такая модель позволяет получить компромисс между высокой скоростью доступа к данным и гибкими возможностями разработки приложений.
Кроме того, вы можете индексировать значения в JSON как обычные столбцы, а также преобразовывать реляционные данные в JSON с помощью FOR JSON и обратно, используя OPENJSON.
habr.com
JSON в Python — Примеры работы модуля JSON
Сразу после появления, JSON быстро стал де факто стандартом обмена информации. Вероятно вы здесь из-за того, что вы хотите переместить данные из одного места в другое. Возможно вы получаете данные через API, или храните их в документной базе данных. Так или иначе, вы заинтересовались JSON, и вам нужно пользоваться им через Python.
Содержание
К счастью, это достаточно тривиальная задача, и как и с большинством тривиальных задач, Python делает все до омерзения простым.
Итак, используем ли мы JSON для хранения и обмена данными? Именно так. Это не более, чем стандартизированный формат, который используется сообществом для передачи данных. Помните, что JSON не является единственным доступным форматом для такой работы, XML и YAML наверное, единственные альтернативные способы, которые стоит упомянуть.
Подробнее про JSON
Не удивительно, что JavaScript Object Notation был вдохновен подмножеством языка программирования JavaScript, связанным с синтаксисом объектного литерала. У них есть отличный сайт, в котором все прекрасно объясняется. Не переживайте: JSON уже давно стал агностиком языка и существует как отдельный стандарт, по этому мы можем убрать JavaScript из этой дискуссии.
Мы собрали ТОП Книг для Python программиста которые помогут быстро изучить язык программирования Python. Список книг: Книги по PythonВ конечном счете, большая часть сообщества приняла JSON благодаря его простоте как для людей, так и для машин.
Смотрите, это JSON!
Структура JSON
Готовьтесь. Я собираюсь показать реальный пример JSON— такой же, какой вы встретите в реальной жизни. Это нормально, подразумевается что JSON является читаемым для любого, кто пользовался С-языками, а Python – это С-язык, так что мы говорим о вас!
{ «firstName»: «Jane», «lastName»: «Doe», «hobbies»: [«running», «sky diving», «singing»], «age»: 35, «children»: [ { «firstName»: «Alice», «age»: 6 }, { «firstName»: «Bob», «age»: 8 } ] }
{ «firstName»: «Jane», «lastName»: «Doe», «hobbies»: [«running», «sky diving», «singing»], «age»: 35, «children»: [ { «firstName»: «Alice», «age»: 6 }, { «firstName»: «Bob», «age»: 8 } ] } |
Как видите, JSON поддерживает примитивные типы, такие как строки python и числа, а также вложенные списки и объекты.
Погодите, это выглядит как словарь Python, верно? На данный момент это достаточно универсальная нотация объектов, и не думаю что UON может так же легко отскакивать от зубов. Кстати, предлагайте альтернативы в комментариях!
НУ что же, вы пережили первый контакт с диким JSON. Теперь вам нужно научиться приручать его!
Python поддерживает JSON
Python содержит встроенный модуль под названием json для кодирования и декодирования данных JSON.
Просто импортируйте модуль в начале вашего файла:
Небольшой словарь
Как правило, процесс кодирования JSON называется сериализация. Этот термин обозначает трансформацию данных в серию байтов (следовательно, серийных) для хранения или передачи по сети. Также вы, возможно, уже слышали о термине «маршалинг», но это уже совсем другая область.
Естественно, десериализация — является противоположным процессом декодирования данных, которые хранятся или направлены в стандарт JSON.
Звучит как много технических терминов. Определенно. Но в реальности, все, о чем мы сейчас говорим — это чтение и написание. Представьте это следующим образом: кодирование это запись данных на диск, в то время как декодирование — это чтение данных в памяти.
Сериализация JSON
Что происходит после того, как компьютер обрабатывает большие объемы информации? Ему нужно принять дамп данных. Соответственно, модуль json предоставляет метод dump() для записи данных в файлы. Также есть метод dumps() для записей в строку Python.
Простые объекты Python переводятся в JSON согласно с весьма интуитивной конверсией.
Python | JSON |
dict | object |
list, tuple | array |
str | string |
int, long, float | number |
True | true |
False | false |
None | null |
Пример сериализации JSON Python
Представьте, что вы работаете с объектом Python в памяти, который выглядит следующим образом:
data = { «president»: { «name»: «Zaphod Beeblebrox», «species»: «Betelgeusian» } }
data = { «president»: { «name»: «Zaphod Beeblebrox», «species»: «Betelgeusian» } } |
Сохранить эту информацию на диск — критично, так что ваша задача — записать на файл.
Используя контекстный менеджер Python, вы можете создать файл под названием data_file.json и открыть его в режиме write (файлы JSON имеют расширение .json).
with open(«data_file.json», «w») as write_file: json.dump(data, write_file)
with open(«data_file.json», «w») as write_file: json.dump(data, write_file) |
Обратите внимание на то, что dump() принимает два позиционных аргумента: (1) объект данных, который сериализуется и (2), файловый объект, в который будут вписаны байты.
Или, если вы склонны продолжать использовать эти сериалзированные данные JSON в вашей программе, вы можете работать как со строкой.
json_string = json.dumps(data)
json_string = json.dumps(data) |
Обратите внимание, что файловый объект является пустым, так как вы на самом деле не выполняете запись на диск. Кроме того, dumps() аналогичен dump().
Ура! У вас получился малыш JSON и вы можете выпустить его в реальный мир, чтобы он вырос большим и сильным.
Несколько полезных аргументов
Помните, что JSON создан таким образом, чтобы быть читаемым для людей. Но читаемого синтаксиса недостаточно, если все слеплено вместе. Кроме этого, ваш стиль программирования скорее всего отличается от моего, и вам будет проще читать код, если он отформатирован по вашему вкусу.
Обратите внимание: Методы dump() и dumps() пользуются одними и теми же аргументами ключевых слов.
Первая опция, которую большинство людей хотят поменять, это пробел. Вы можете использовать аргумент indent для определения размера отступа вложенных структур. Ощутите разницу лично, используя данные, упомянутые выше и выполните следующие команды в консоли:
json.dumps(data) json.dumps(data, indent=4)
json.dumps(data) json.dumps(data, indent=4) |
Еще один вариант форматирования — это аргумент separators. По умолчанию, это двойной кортеж строк разделителя («, «, «: «), но обычно в качестве альтернативы для компактного JSON является («,», «:»). Взгляните на пример JSON еще раз, чтобы понять, где в игру вступают разделители.
Есть и другие аргументы, такие как sort_keys, но я не имею понятия, что он делает. Вы можете найти полный список в документации, если вам интересно.
Десериализация JSON
Отлично, похоже вам удалось поймать экземпляр дикого JSON! Теперь нам нужно предать ему форму. В модуле json вы найдете load() и loads() для превращения кодированных данных JSON в объекты Python.
Как и сериализация, есть простая таблица конверсии для десериализации, так что вы можете иметь представление о том, как все выглядит.
JSON | Python |
object | dict |
array | list |
string | str |
number (int) | int |
number (real) | float |
true | True |
false | False |
null | None |
Технически, эта конверсия не является идеальной инверсией таблицы сериализации. По сути, это значит что если вы кодируете объект сейчас, а затем декодируете его в будущем, вы можете не получить тот же объект назад. Я представляю это как своего рода телепортацию: мои молекулы распадаются в точке А и собираются в точке Б. Буду ли я тем же самым человеком?
В реальности, это как попросить одного друга перевести что-нибудь на японский, а потом попросить другого друга перевести это обратно на русский. В любом случае, самым простым примером будет кодировать кортеж и получить назад список после декодирования, вот так:
blackjack_hand = (8, «Q») encoded_hand = json.dumps(blackjack_hand) decoded_hand = json.loads(encoded_hand) print(blackjack_hand == decoded_hand) # False print(type(blackjack_hand)) # <class ‘tuple’> print(type(decoded_hand)) # <class ‘list’> print(blackjack_hand == tuple(decoded_hand)) # True
blackjack_hand = (8, «Q») encoded_hand = json.dumps(blackjack_hand) decoded_hand = json.loads(encoded_hand)
print(blackjack_hand == decoded_hand) # False
print(type(blackjack_hand)) # <class ‘tuple’> print(type(decoded_hand)) # <class ‘list’>
print(blackjack_hand == tuple(decoded_hand)) # True |
Пример десериализации JSON Python
На этот раз, представьте что у вас есть некие данные, хранящиеся на диске, которыми вы хотите манипулировать в памяти. Вам все еще нужно будет воспользоваться контекстным менеджером, но на этот раз, вам нужно будет открыть существующий data_file.json в режиме для чтения.
with open(«data_file.json», «r») as read_file: data = json.load(read_file)
with open(«data_file.json», «r») as read_file: data = json.load(read_file) |
Здесь все достаточно прямолинейно, но помните, что результат этого метода может вернуть любые доступные типы данных из таблицы конверсий. Это важно только в том случае, если вы загружаете данные, которые вы ранее не видели. В большинстве случаев, корневым объектом будет dict или list.
Если вы внесли данные JSON из другой программы, или полученную каким-либо другим способом строку JSON форматированных данных в Python, вы можете легко десериализировать это при помощи loads(), который естественно загружается из строки:
json_string = «»» { «researcher»: { «name»: «Ford Prefect», «species»: «Betelgeusian», «relatives»: [ { «name»: «Zaphod Beeblebrox», «species»: «Betelgeusian» } ] } } «»» data = json.loads(json_string)
json_string = «»» { «researcher»: { «name»: «Ford Prefect», «species»: «Betelgeusian», «relatives»: [ { «name»: «Zaphod Beeblebrox», «species»: «Betelgeusian» } ] } } «»»
data = json.loads(json_string) |
Ву а ля! Вам удалось укротить дикого JSON, теперь он под вашим контролем. Но что вы будете делать с этой силой — остается за вами. Вы можете кормить его, выращивать, и даже научить новым приемам. Не то чтобы я не доверяю вам, но держите его на привязи, хорошо?
Пример работы с JSON Python
Для тестового API, мы воспользуемся JSONPlaceholder, отличный источник фейковых данных JSON для практических целей.
Для начала, создайте файл под названием scratch.py, или как вам удобно. Здесь я не могу вас контролировать.
Вам нужно выполнить запрос API в сервис JSONPlaceholder, так что просто используйте пакет requests, чтобы он сделал за вас всю грязную работу. Добавьте следующие импорты вверху файла:
import json import requests
import json import requests |
Теперь вам предстоит поработать со списком TODOs, потому что… это своего рода обряд посвящения, вроде того.
Идем дальше и создаем запрос в API JSONPlaceholder для конечной точки GET /todos. Если вы слабо знакомы с запросами, есть очень удобный метод json(), который выполнит за вас всю работу, но вы можете попрактиковаться в использовании модуля json для десериализации атрибута текста объекта response. Это должно выглядеть следующим образом:
response = requests.get(«https://jsonplaceholder.typicode.com/todos») todos = json.loads(response.text)
response = requests.get(«https://jsonplaceholder.typicode.com/todos») todos = json.loads(response.text) |
Не верится, что это работает? Хорошо, запустите файл в интерактивном режиме и проверьте лично. Пока вы там, проверьте тип todos. Если вам любопытно, обратите внимание на первые 10 элементов в списке.
response = requests.get(«https://jsonplaceholder.typicode.com/todos») todos = json.loads(response.text) print(todos == response.json()) # True print(type(todos)) # <class ‘list’> print(todos[:10]) # …
response = requests.get(«https://jsonplaceholder.typicode.com/todos») todos = json.loads(response.text)
print(todos == response.json()) # True print(type(todos)) # <class ‘list’>
print(todos[:10]) # … |
Как видите, никто вас не обманывает, и мы ценим здравый скептицизм.
Что такое интерактивный режим? Я уже думал вы не спросите! Вы знакомы с тем, что приходится постоянно прыгать туда-сюда между вашим редактором и терминалом? Мы, хитрые питонисты, используем интерактивный флаг -i, когда запускаем скрипт. Это отличный небольшой трюк для тестирования кода, так как он запускает скрипт, и затем открывает интерактивную командную строку с доступом ко всем данным скрипта!
Хорошо, теперь перейдем к действиям. Вы можете видеть структуру данных полученную от тестового API, посетив адрес в браузере https://jsonplaceholder.typicode.com/todos:
{ «userId»: 1, «id»: 1, «title»: «delectus aut autem», «completed»: false }
{ «userId»: 1, «id»: 1, «title»: «delectus aut autem», «completed»: false } |
Здесь несколько пользователей, каждый из которых имеет уникальный userId, а каждая задача имеет свойство Boolean. Можете определить, какие пользователи выполнили большую часть задач?
response = requests.get(«https://jsonplaceholder.typicode.com/todos») todos = json.loads(response.text) # Соотношение userId с числом выполненных пользователем задач. todos_by_user = {} # Увеличение выполненных задач каждым пользователем. for todo in todos: if todo[«completed»]: try: # Увеличение количества существующих пользователей. todos_by_user[todo[«userId»]] += 1 except KeyError: # Новый пользователь, ставим кол-во 1. todos_by_user[todo[«userId»]] = 1 # Создание отсортированного списка пар (userId, num_complete). top_users = sorted(todos_by_user.items(), key=lambda x: x[1], reverse=True) #Получение максимального количества выполненных задач. max_complete = top_users[0][1] # Создание списка всех пользователей, которые выполнили # максимальное количество задач. users = [] for user, num_complete in top_users: if num_complete < max_complete: break users.append(str(user)) max_users = » and «.join(users)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | response = requests.get(«https://jsonplaceholder.typicode.com/todos») todos = json.loads(response.text)
# Соотношение userId с числом выполненных пользователем задач. todos_by_user = {}
# Увеличение выполненных задач каждым пользователем. for todo in todos: if todo[«completed»]: try: # Увеличение количества существующих пользователей. todos_by_user[todo[«userId»]] += 1 except KeyError: # Новый пользователь, ставим кол-во 1. todos_by_user[todo[«userId»]] = 1
# Создание отсортированного списка пар (userId, num_complete). top_users = sorted(todos_by_user.items(), key=lambda x: x[1], reverse=True)
#Получение максимального количества выполненных задач. max_complete = top_users[0][1]
# Создание списка всех пользователей, которые выполнили # максимальное количество задач. users = [] for user, num_complete in top_users: if num_complete < max_complete: break users.append(str(user))
max_users = » and «.join(users) |
Да, да, ваша версия лучше, но суть в том, что теперь вы можете манипулировать данными JSON как нормальным объектом Python!
Не знаю как вы, но я запустил скрипт в интерактивном режиме еще раз, и получил следующий результат:
s = «s» if len(users) > 1 else «» print(f»user{s} {max_users} completed {max_complete} TODOs») # users 5 and 10 completed 12 TODOs
s = «s» if len(users) > 1 else «» print(f»user{s} {max_users} completed {max_complete} TODOs») # users 5 and 10 completed 12 TODOs |
Это круто, и все такое, но мы занимаемся изучением JSON. В качестве вашей последней задачи, вы создадите файл JSON, который содержит готовые задачи (TODO) для каждого пользователя, который выполнил максимальное количество задач. Здесь мы использовали F-Строки Python.
Все, что вам нужно сделать, это отфильтровать задачи и вписать итоговый список в файл. Ради оригинальности, вы можете назвать файл выдачи filtered_data_file.json. Существует много способов сделать это, вот один из них:
# Определить функцию для фильтра выполненных задач # с пользователями с максимально выполненными задачами. def keep(todo): is_complete = todo[«completed»] has_max_count = todo[«userId»] in users return is_complete and has_max_count # Записать отфильтрованные задачи в файл with open(«filtered_data_file.json», «w») as data_file: filtered_todos = list(filter(keep, todos)) json.dump(filtered_todos, data_file, indent=2)
# Определить функцию для фильтра выполненных задач # с пользователями с максимально выполненными задачами. def keep(todo): is_complete = todo[«completed»] has_max_count = todo[«userId»] in users return is_complete and has_max_count
# Записать отфильтрованные задачи в файл with open(«filtered_data_file.json», «w») as data_file: filtered_todos = list(filter(keep, todos)) json.dump(filtered_todos, data_file, indent=2) |
Отлично, теперь вы избавились от всех данных, которые вам не нужны и сохранили необходимое для нового файла!
Запустите скрипт еще раз и проверьте filtered_data_file.json, чтобы убедиться в том, что все работает. Он будет в той же папке, что и scratch.py, когда вы запустите его.
Теперь, когда вы зашли так далеко, вы начинаете понимать что коснулись темы с большим потенциалом, не так ли? Не зазнавайтесь: скромность сестра таланта. Хотя и не могу не согласиться. Пока что мы работали в плавном потоке, но под конец мы можем поддать газку.
Кодирование и декодирование объектов Python
Что случается, когда мы пытаемся сериализировать класс Elf из приложения Dungeons & Dragons, с которым вы работаете?
class Elf: def __init__(self, level, ability_scores=None): self.level = level self.ability_scores = { «str»: 11, «dex»: 12, «con»: 10, «int»: 16, «wis»: 14, «cha»: 13 } if ability_scores is None else ability_scores self.hp = 10 + self.ability_scores[«con»]
class Elf: def __init__(self, level, ability_scores=None): self.level = level self.ability_scores = { «str»: 11, «dex»: 12, «con»: 10, «int»: 16, «wis»: 14, «cha»: 13 } if ability_scores is None else ability_scores self.hp = 10 + self.ability_scores[«con»] |
Ничего удивительного, Возникла ошибка, что класс Elf нельзя сериализировать:
elf = Elf(level=4) json.dumps(elf) TypeError: Object of type ‘Elf’ is not JSON serializable
elf = Elf(level=4) json.dumps(elf) TypeError: Object of type ‘Elf’ is not JSON serializable |
Хотя, модуль json может обрабатывать большинство типов Python, он не понимает, как кодировать пользовательские типы данных по умолчанию. Это как пытаться поместить кубик в круглое отверстие — вам понадобится бензопила и надзор специалиста.
Упрощение структур данных
Сейчас вопрос в том, что делать с более сложными структурами данных. Например, вы можете попробовать кодировать и декодировать JSON вручную, но есть более разумное решение, которое избавит вас от лишней работы. Вместо того, чтобы идти непосредственно от пользовательского типа данных к JSON, вы можете перейти к промежуточному шагу.
Все что вам нужно, это отобразить ваши данные в контексте встроенных типов, которые изначально понятны json. По сути, вы переводите более сложный объект в его упрощенное представление, которое модуль json затем переводит в JSON.
Это наглядно представляется в математике: А = В, и В = С, значит А = С.
Чтобы добиться этого, вам нужен сложный объект для работы. Вы можете использовать любой пользовательский класс на ваш вкус, но Python имеет встроенный тип под названием complex, для представления сложных чисел, и он не может быть сериализированным по умолчанию. Итак, ради этих примеров, ваш сложный объект станет сложным объектом. Уже запутались?
z = 3 + 8j print(type(z)) # <class ‘complex’> json.dumps(z) TypeError: Object of type ‘complex’ is not JSON serializable
z = 3 + 8j print(type(z)) # <class ‘complex’>
json.dumps(z) TypeError: Object of type ‘complex’ is not JSON serializable |
Откуда приходят комплексные числа? Когда реальное число и представляемое число очень любят друг друга, они складываются вместе для создания числа, которое (справедливо) называется комплексным.
Хороший вопрос, который стоит задать себе при работе со сложными типами: «Какой минимальный объем информации необходим для воссоздания этого объекта?» В случае со комплексными числами, вам нужно знать только реальное и представляемое число, доступ к которым (в качестве атрибутов) доступен в объекте complex:
z = 3 + 8j print(z.real) # 3.0 print(z.imag) # 8.0
z = 3 + 8j
print(z.real) # 3.0 print(z.imag) # 8.0 |
Передачи одних и тех же чисел в сложный конструктор достаточно для удовлетворения оператора сравнения __eq__:
z = 3 + 8j print( complex(3, 8) == z ) # True
z = 3 + 8j
print( complex(3, 8) == z ) # True |
Разбивать пользовательские типы данных на их составляющие компоненты — критически важно как для процесса сериализации, так и для десериализации.
Кодирование пользовательских типов
Для перевода пользовательского объекта в JSON, все что вам нужно — это предоставить функцию кодирования параметру по умолчанию метода dump(). Модуль json вызовет эту функцию для любых объектов, которые не являются естественно сериализируемыми. Вот простая функция декодирования, которую вы можете использовать на практике:
def encode_complex(z): if isinstance(z, complex): return (z.real, z.imag) else: type_name = z.__class__.__name__ raise TypeError(f»Object of type ‘{type_name}’ is not JSON serializable»)
def encode_complex(z): if isinstance(z, complex): return (z.real, z.imag) else: type_name = z.__class__.__name__ raise TypeError(f»Object of type ‘{type_name}’ is not JSON serializable») |
Обратите внимание на то, что ожидается получение ошибки TypeError, если вы не получите ожидаемый тип объекта. Таким образом, вы избегаете случайной сериализации любых пользовательских типов. Теперь вы можете кодировать сложные объекты самостоятельно!
>>> json.dumps(9 + 5j, default=encode_complex) ‘[9.0, 5.0]’ >>> json.dumps(elf, default=encode_complex) TypeError: Object of type ‘Elf’ is not JSON serializable
>>> json.dumps(9 + 5j, default=encode_complex) ‘[9.0, 5.0]’
>>> json.dumps(elf, default=encode_complex) TypeError: Object of type ‘Elf’ is not JSON serializable |
Почему мы кодируем комплексное число как кортеж? Хороший вопрос. Это определенно не является единственными выбором, впрочем, как и не является лучшим выбором. Фактически, это не может быть хорошим отображением, если вы планируете декодировать объект в будущем, что вы и увидите дальше.
Еще один частый подход — создать дочерний класс JSONEncoder и переопределить его метод default():
class ComplexEncoder(json.JSONEncoder): def default(self, z): if isinstance(z, complex): return (z.real, z.imag) else: super().default(self, z)
class ComplexEncoder(json.JSONEncoder): def default(self, z): if isinstance(z, complex): return (z.real, z.imag) |
python-scripts.com