TGViewer
C# Heppard C# Heppard @csharp_gepard · 1.65K subscribers
Post #155 2.44K
JsonPath в .NET #решение

Представим себе, что есть сервис, который умеет получать данные из Kafka и складывать полученные данные в БД. Без программирования, просто декларативным указанием topic и таблицы в БД. То есть:

1. Сервис работает по запросу (job или unit-of-work).
2. При создании job описывается маппинг данных из Kafka в нужную таблицу.
3. Описывается фильтрация и преобразовывает данных из Kafka так, как пользователю удобно. Ну чтобы не заниматься этим при каждом запросе в БД.

То есть, во-первых, нужен вменяемый API, которым удобно пользоваться. Во-вторых, нужно описание маппинга полей сообщения из Kafka в поля Data-base-object (DBO). Ну и всякая фильтрация (например, отсечение удалённых), выбор определённых полей и некие операции над ними.

Например, нам нужно взять подразделения компании, перенести часть нужных нам полей, а, также, налету, создать поле, в котором лежит полный путь до этого подразделения в дереве (например, "Бизнес-юнит 3/Департамент 2/Подразделение 1"). Представим себе, что в исходном сообщении эти данные есть, но в виде массива родительских подразделений. То есть нужно взять их названия, правильно отсортировать и соединить в строку.

Какой же интерфейс предоставить программистам, чтобы они могли это сделать? Правильно, формализованный JsonPath (RFC). Конечный пользователь тоже не пострадает, так как сможет, с помощью программистов, натыкать такое на UI.

Когда сервис будет вычитывать сообщение из Kafka, исходное сообщение будет преобразовано, размаплено по нужным полям DBO и помещено в базу. Маппинг, при создании job будет выглядеть примерно так.
{
"id": "$.id",
"1c_id": "$.1c.id",
"full_path": "join(sort($.parents, @.lvl), '/')",
"name": "$.name",
"manager_id": "$.manager.oauth.id",
"filters": [
"$.is_deleted == false",
"$.draft == false"
]
}


Но чтобы сделать этот маппинг, увы, нужно приложить усилия. Дело в том, что стандартная (с некоторых пор) библиотека для работы с json в .NET это System.Text.Json. А он не умеет выбирать узел по JsonPath. Опустим и то, что мало кто из библиотек умеет работать с функциями высшего порядка (см. full_path в примере), но это, со скрипом, можно сделать самому.

Основная задача - получение нужных узлов исходного сообщения в Kafka по выражению JsonPath. Для решения этой задачи можно найти несколько библиотек: непотопляемый Newtonsoft.Json, модный Hyperbee.Json, хмурый JsonCons.Net и популярный JsonPath.Net).

Так как сервис представляется весьма нагруженным, а поиск и преобразования по JsonPath - частыми, нужно выбрать именно ту библиотеку, которая работает быстро и, при этом, потребляет мало памяти. Результаты на скриншоте. Кажется, что Newtonsoft.Json или Hyperbee.Json - весьма неплохой выбор, по скорости и потреблению памяти.

Естественно, все эти библиотеки отличаются функционалом и возможностями расширения (например, в данном примере нужно добавлять свои функции к JsonPath для мутации данных). Тот же Newtonsoft.Json огромная и уважаемая библиотека. Однако, если нужно только парсить JsonPath, то выбор похож на очевидный.

Бенчмарк вот тут.

P.S.: Банчмарки включают в себя создание JsonDocument, JsonNode и JObject, чтобы приблизиться к реальной ситуации. В реальности сервис получает одну из этих структур данных и работает с ней. Если эти штуки предварительно создавать, то, в принципе, результат не изменится. Единственное, что изменится - пропадёт аллокация.
P.P.S.: Пакет Microsoft.AspNetCore.JsonPatch исключён из тестирования, так как основывается на Newtonsoft.Json.
P.P.P.S.: Ребята из Hyperbee.Json, кажется, выложили на nuget библиотеку, которая скомпилирована в Debug. Исправили.
  • 👍 12
  • 👏 4
  • ❤ 3
  • 🔥 1
More from @csharp_gepard
  1. Mar 13, 2026Ozon Tech Community .NET Meetup 24 марта, лофт Casa Picassa, 19:00 Ищем способы бороться с…
  2. Jan 20, 2026Ещё одна история про память #отдых Судя по комментариям специалистов и ценам на RAM в мага…
  3. Nov 25, 2025FastEnum #скорость Иногда нам нужно не просто быстро, а очень быстро. В этот момент в дело…
  4. Nov 20, 2025UnsafeAccessor #скорость Иногда возникает странное желание изменять приватные поля в класс…
  5. Nov 17, 2025Latency numbers every programmer should know Я всё время теряю эти циферки, особенно когда…
  6. Oct 29, 2025Dictionary.TryGetValue #скорость Уж сколько лет прошло и, вроде, все это знают. Но, тем не…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →