Есть ли язык запросов для JSON?


227

Существует ли (примерно) SQL или XQuery-подобный язык для запросов JSON?

Я имею в виду очень маленькие наборы данных, которые хорошо отображаются в JSON, где было бы неплохо легко отвечать на запросы, такие как «каковы все значения X, где Y> 3», или выполнять обычные операции типа SUM / COUNT.

Как полностью вымышленный пример, примерно так:

[{"x": 2, "y": 0}}, {"x": 3, "y": 1}, {"x": 4, "y": 1}]

SUM(X) WHERE Y > 0     (would equate to 7)
LIST(X) WHERE Y > 0    (would equate to [3,4])

Я думаю, что это будет работать как на стороне клиента, так и на стороне сервера, при этом результаты будут преобразованы в соответствующую структуру данных для конкретного языка (или, возможно, сохранены как JSON)

Быстрый поиск в Google позволяет предположить, что люди подумали об этом и реализовали несколько вещей ( JAQL ), но пока что не появилось стандартного использования или набора библиотек. Хотя каждая функция довольно проста для реализации самостоятельно, если кто-то уже сделал это правильно, я не хочу заново изобретать колесо.

Какие-либо предложения?

Редактировать: Это действительно может быть плохой идеей, или JSON может быть слишком универсальным форматом для того, о чем я думаю. Причина, по которой мне нужен язык запросов вместо того, чтобы просто выполнять функции суммирования / etc напрямую по мере необходимости, заключается в том, что я надеюсь построить запросы динамически основаны на пользовательском вводе. Вроде как аргумент, что «нам не нужен SQL, мы можем просто написать нужные нам функции». В конечном итоге это либо выходит из-под контроля, либо вы в конечном итоге пишете свою собственную версию SQL по мере продвижения вперед и дальше. (Хорошо, я знаю, что это немного глупый аргумент, но вы поняли ...)


У меня такая потребность тоже есть. Мне нужно сопоставить входящие запросы JSON по определенным значениям в определенных местах в дереве объектов. На самом деле запрос должен быть настроен (опытным) пользователем. Текущий обходной путь заключается в создании временного XML из JSON и применении XPath.
Владимир Дюжев

1
Это скорее инструмент оболочки, но jq ( stedolan.github.io/jq ) отлично подходит для изучения данных json. Попробуйте это на детской площадке: jqplay.org
jtmoulia

Существует веб-инструмент, позволяющий запускать запросы SQL на общедоступных каналах JSON или API-интерфейсах на sqall.co .
Stack Man


Ответы:


91

Конечно, как насчет:

Все они, кажется, немного в стадии разработки, но работают в некоторой степени. Они также похожи на XPath и XQuery концептуально; хотя XML и JSON имеют разные концептуальные модели (иерархическая или объектная / структурная).

РЕДАКТИРОВАТЬ Сентябрь 2015: На самом деле, теперь существует стандарт JSON Pointer, который позволяет очень простой и эффективный обход контента JSON. Он не только формально указан, но и поддерживается многими библиотеками JSON. Поэтому я бы назвал это действительно полезным стандартом, хотя из-за его ограниченной выразительности он может или не может считаться языком запросов как таковым.


77
иными словами, ничего стандартного и стабильного ... :-(
Владимир Дюжев

Говоря о стандарте, я услышал слух, что XQuery 3.1 может быть расширен для поддержки запросов JSON (аналогично JSONiq ). Конечно, это может занять некоторое время, поскольку XQuery 3.0 еще не выпущен официально.
Жюльен Рибон

О, милосердие, я определенно надеюсь, что нет. Все попытки XML-> JSON, которые я видел, были ужасными путаницами - информационные модели несовместимы. Но я хотел бы видеть JQuery, использующий те же идеи, части синтаксиса; только что должным образом изменен на информационную модель JSON.
StaxMan

1
Для тех, кто ищет реализацию JSONPath в Ruby: github.com/joshbuddy/jsonpath
Роберт Росс

@ GôTô: Использование MongoDB, если у вас есть такая свобода, кажется жизнеспособным подходом. (см. ответ ниже для примера того, как перевести запрос во встроенную оболочку)
serv-inc

48

Я бы порекомендовал мой проект, над которым я работаю, под названием jLinq . Я ищу отзывы, поэтому мне было бы интересно услышать, что вы думаете.

Если позволяет вам писать запросы, похожие на то, как вы бы в LINQ ...

var results = jLinq.from(records.users)

    //you can join records
    .join(records.locations, "location", "locationId", "id")

    //write queries on the data
    .startsWith("firstname", "j")
    .or("k") //automatically remembers field and command names

    //even query joined items
    .equals("location.state", "TX")

    //and even do custom selections
    .select(function(rec) {
        return {
            fullname : rec.firstname + " " + rec.lastname,
            city : rec.location.city,
            ageInTenYears : (rec.age + 10)
        };
    });

Это также полностью расширяемый!

Документация все еще находится в стадии разработки, но вы все еще можете попробовать ее онлайн.


@hugoware: есть ли документация для этого. Есть ли какие-либо запросы, кроме .starts () (например, содержит?)
Rikki

5
Последнее обновление 8 лет назад, и нет ответа на вопрос, мертв ли ​​проект 5 лет назад ... Я думаю, что проект мертв.
Cfc


14

jmespath работает довольно легко и хорошо, http://jmespath.org/ Он используется Amazon в интерфейсе командной строки AWS, поэтому он должен быть достаточно стабильным.


5
В то же время на той же странице: «Если вам нужны более продвинутые функции, которые могут быть невозможны с --query, вы можете проверить jq, процессор JSON командной строки». Таким образом, похоже, что AWS использует jmespathэтот --queryпараметр, но рекомендует использовать его jqдля командной строки. docs.aws.amazon.com/cli/latest/userguide/…
wisbucky

10

JQ является J SON д языком uery, в основном предназначен для командной строки , но с креплениями для широкого спектра языков программирования (Java, Node.js, PHP, ...) и даже доступных в браузере через JQ-сеть .

Вот несколько иллюстраций, основанных на оригинальном вопросе, который привел этот JSON в качестве примера:

 [{"x": 2, "y": 0}}, {"x": 3, "y": 1}, {"x": 4, "y": 1}]

СУММА (X) ГДЕ Y> 0 (будет равно 7)

map(select(.y > 0)) | add

СПИСОК (X) ГДЕ Y> 0 (будет соответствовать [3,4])

map(.y > 0)

Синтаксис JQ расширяет синтаксис JSON

Каждое выражение JSON является допустимым выражением jq, а такие выражения, как [1, (1+1)]и {"a": (1 + 1)} `, иллюстрируют, как jq расширяет синтаксис JSON.

Более полезным примером является выражение jq:

{a,b}

который, учитывая значение JSON {"a":1, "b":2, "c": 3}, оценивается как {"a":1, "b":2}.


8

Встроенный array.filter()метод делает большинство из этих так называемых библиотек запросов javascript устаревшими

Вы можете поместить в делегат столько условий, сколько вы можете себе представить: простое сравнение, старты с и т. Д. Я не тестировал, но вы, вероятно, могли бы также вложить фильтры для запросов внутренних коллекций.


5
array.filter()является частью JavaScript, а не JSON.
Иэн Самуэль Маклин, старейшина

2
JSON является подмножеством JavaScript, но есть много языков, которые поддерживают как JSON, так и массивы, и в которых реализован метод фильтра массива, так что это правильная точка.
Дакаб

7

Если вы используете .NET, то Json.NET поддерживает запросы LINQ поверх JSON. Этот пост имеет несколько примеров. Поддерживает фильтрацию, отображение, группировку и т. Д.


7

ObjectPath - это простой и лёгкий язык запросов для документов JSON сложной или неизвестной структуры. Он похож на XPath или JSONPath, но гораздо более мощный благодаря встроенным арифметическим вычислениям, механизмам сравнения и встроенным функциям.

пример

Версия Python является зрелой и используется в производстве. JS все еще находится в бета-версии.

Вероятно, в ближайшее время мы предоставим полноценную версию Javascript. Мы также хотим развивать его дальше, чтобы он мог служить более простой альтернативой запросам Монго.


1
За исключением того, что у него почти нет документации, поэтому сложно найти способ сделать что-нибудь, например, найти элементы с текстом, например.
Джеймс О'Брайен

1
@ JamesO'Brien Спасибо за ваше замечание - если вы находите ссылку бесполезной и имеете какую-то конкретную проблему, дайте нам знать здесь - кто-то попытается помочь. В настоящее время мы работаем над тем, чтобы сделать документы более удобными в использовании, я буду рад вашим комментариям.
Эла Беднарек

Спасибо, я ценю это. Я хотел бы использовать. В настоящее время я использую ashphy.com/JSONPathOnlineEvaluator ?
Джеймс О'Брайен

Не могу понять, как использовать это с Javascript из-за полного отсутствия документации.
user3670743

Мы ищем вкладчиков, чтобы помочь с этим. Вы можете написать на Github или в google groups groups.google.com/forum/#!members/objectpath то, что вы пытаетесь достичь, и я уверен, что кто-то ответит на ваши вопросы.
Эла Беднарек

6

Другой способ посмотреть на это - использовать mongoDB. Вы можете сохранить свой JSON в mongo, а затем запросить его с помощью синтаксиса запроса mongodb.


MongoDB так приятно использовать. Смотрите ответ ниже для примера того, как использовать.
Серв-ин

4

Хорошо, этот пост немного старый, но ... если вы хотите сделать SQL-подобный запрос в нативном JSON (или JS-объектах) для JS-объектов, взгляните на https://github.com/deitch/searchjs

Это и язык jsql, написанный полностью на JSON, и эталонная реализация. Вы можете сказать: «Я хочу найти все объекты в массиве с именем ===« Джон »&& age === 25 как:

{name:"John",age:25,_join:"AND"}

Ссылочная реализация searchjs работает в браузере так же, как и пакет npm узла

npm install searchjs

Это также может делать такие вещи, как сложные объединения и отрицание (НЕ). Это изначально игнорирует случай.

Это еще не делает суммирование или подсчет, но, вероятно, легче сделать те, кто снаружи.


3

Вот несколько простых библиотек JavaScript, которые также сделают свое дело:

  • Dollar Q - хорошая легкая библиотека. Он знаком с синтаксисом цепочки, популярным в jQuery, и составляет всего 373 SLOC.
  • SpahQL - это полнофункциональный язык запросов с синтаксисом, похожим на XPath ( домашняя страница , Github
  • jFunk - это язык запросов в процессе, с синтаксисом, похожим на селекторы CSS / jQuery. Это выглядело многообещающе, но не имело никакого развития кроме его в начальном коммите.

  • (добавлено 2014): инструмент командной строки jq имеет аккуратный синтаксис, но, к сожалению, это библиотека ac. Пример использования:

    < package.json jq '.dependencies | to_entries | .[] | select(.value | startswith("git")) | .key'


3

В MongoDB именно так и будет работать (в оболочке mongo существуют драйверы для выбранного вами языка).

db.collection.insert({"x": 2, "y": 0}); // notice the ':' instead of ','
db.collection.insert({"x": 3, "y": 1});
db.collection.insert({"x": 4, "y": 1});

db.collection.aggregate([{$match: {"y": {$gt: 0}}}, 
                         {$group: {_id: "sum", sum: {$sum: "$x"}}}]);
db.collection.aggregate([{$match: {"y": {$gt: 0}}}, 
                         {$group: {_id: "list", list: {$push: "$x"}}}]);

Первые три команды вставляют данные в вашу коллекцию. (Просто запустите mongodсервер и соединитесь с mongoклиентом.)

Следующие два обрабатывают данные. $matchфильтры, $groupприменяет sumи list, соответственно.


2

Насколько я могу судить, SpahQL является наиболее перспективным и продуманным из них. Я настоятельно рекомендую проверить это.


2


Я только что закончил выпускную версию клиентской JS-lib (defiant.js), которая делает то, что вы ищете. С помощью defiant.js вы можете запросить структуру JSON с помощью знакомых вам выражений XPath (нет новых синтаксических выражений, как в JSONPath).

Пример того, как это работает (см. Это в браузере здесь http://defiantjs.com/defiant.js/demo/sum.avg.htm ):

var data = [
       { "x": 2, "y": 0 },
       { "x": 3, "y": 1 },
       { "x": 4, "y": 1 },
       { "x": 2, "y": 1 }
    ],
    res = JSON.search( data, '//*[ y > 0 ]' );

console.log( res.sum('x') );
// 9
console.log( res.avg('x') );
// 3
console.log( res.min('x') );
// 2
console.log( res.max('x') );
// 4

Как видите, DefiantJS расширяет глобальный объект JSON функцией поиска, а возвращаемый массив поставляется с агрегатными функциями. DefiantJS содержит несколько других функций, но они выходят за рамки этого предмета. В любом случае, вы можете протестировать библиотеку с помощью клиентского XPath Evaluator. Я думаю, что люди, не знакомые с XPath, сочтут этот оценщик полезным.
http://defiantjs.com/#xpath_evaluator

Дополнительная информация о defiant.js
http://defiantjs.com/
https://github.com/hbi99/defiant.js

Я надеюсь, что вы найдете это полезным ... С уважением


Возможно ли в настоящее время получить полный путь к результатам?
КсенияСи

2
  1. У Google есть проект под названием lovefield ; только что узнал об этом, и это выглядит интересно, хотя это более сложный процесс, чем просто добавление подчеркивания или lodash.

    https://github.com/google/lovefield

Lovefield - это механизм реляционных запросов, написанный на чистом JavaScript. Он также предоставляет помощь с сохранением данных на стороне браузера, например, используя IndexedDB для локального хранения данных. Он обеспечивает SQL-подобный синтаксис и работает в разных браузерах (в настоящее время поддерживается Chrome 37+, Firefox 31+, IE 10+ и Safari 5.1 + ...


  1. Еще одна интересная недавняя запись в этом пространстве называется jinqJs .

    http://www.jinqjs.com/

    Кратко рассмотрев примеры , это выглядит многообещающе, и документ API выглядит хорошо написанным.


function isChild(row) {
  return (row.Age < 18 ? 'Yes' : 'No');
}

var people = [
  {Name: 'Jane', Age: 20, Location: 'Smithtown'},
  {Name: 'Ken', Age: 57, Location: 'Islip'},
  {Name: 'Tom', Age: 10, Location: 'Islip'}
];

var result = new jinqJs()
  .from(people)
  .orderBy('Age')
  .select([{field: 'Name'}, 
     {field: 'Age', text: 'Your Age'}, 
     {text: 'Is Child', value: isChild}]);

jinqJs - это небольшая, простая, легкая и расширяемая библиотека javaScript, которая не имеет зависимостей. jinqJs предоставляет простой способ выполнения SQL-подобных запросов к массивам javaScript, коллекциям и веб-службам, которые возвращают ответ JSON. jinqJs аналогичен лямбда-выражению Microsoft для .Net и предоставляет аналогичные возможности для запросов к коллекциям, используя синтаксис SQL и функциональность предикатов. Целью jinqJs является предоставление SQL-подобного опыта программистам, знакомым с запросами LINQ.


1

Я поддержу идею использования вашего собственного javascript, но для чего-то более сложного вы можете взглянуть на данные dojo . Не использовал его, но, похоже, он дает вам примерно тот интерфейс запроса, который вы ищете.


1

Текущая реализация Jaql нацелена на обработку больших данных с использованием кластера Hadoop, так что это может быть больше, чем вам нужно. Тем не менее, он легко запускается без кластера Hadoop (но все же для его компиляции требуется код Hadoop и его зависимости, которые в основном включены). Небольшая реализация Jaql, которая может быть встроена в Javascript и браузер, будет отличным дополнением к проекту.

Ваши примеры выше легко написаны на jaql:

$data = [{"x": 2, "y": 0}, {"x": 3, "y": 1}, {"x": 4, "y": 1}];

$data -> filter $.y > 0 -> transform $.x -> sum(); // 7

$data -> filter $.y > 0 -> transform $.x; // [3,4]

Конечно, есть и многое другое. Например:

// Compute multiple aggregates and change nesting structure:
$data -> group by $y = $.y into { $y, s:sum($[*].x), n:count($), xs:$[*].x}; 
    // [{ "y": 0, "s": 2, "n": 1, "xs": [2]   },
    //  { "y": 1, "s": 7, "n": 2, "xs": [3,4] }]

// Join multiple data sets:
$more = [{ "y": 0, "z": 5 }, { "y": 1, "z": 6 }];
join $data, $more where $data.y == $more.y into {$data, $more};
    // [{ "data": { "x": 2, "y": 0 }, "more": { "y": 0, "z": 5 }},
    //  { "data": { "x": 3, "y": 1 }, "more": { "y": 1, "z": 6 }},
    //  { "data": { "x": 4, "y": 1 }, "more": { "y": 1, "z": 6 }}]

Jaql можно скачать / обсудить по адресу http://code.google.com/p/jaql/.


1

Вы также можете использовать Underscore.js, который является в основном библиотекой швейцарского ножа для управления коллекциями. Используя _.filter, _.pluck, _.reduceвы можете сделать SQL-подобных запросов.

var data = [{"x": 2, "y": 0}, {"x": 3, "y": 1}, {"x": 4, "y": 1}];

var posData = _.filter(data, function(elt) { return elt.y > 0; });
// [{"x": 3, "y": 1}, {"x": 4, "y": 1}]

var values = _.pluck(posData, "x");
// [3, 4]

var sum = _.reduce(values, function(a, b) { return a+b; });
// 7

Underscore.js работает как на стороне клиента, так и на стороне сервера и является заметной библиотекой.

Вы также можете использовать Lo-Dash, который является форком Underscore.js с лучшими характеристиками.


1

Когда бы ни было возможно, я бы переместил все запросы к серверной части сервера (к базе данных SQL или другому собственному типу базы данных). Причина в том, что это будет быстрее и более оптимизировано для выполнения запросов.

Я знаю, что jSON может быть автономным и может существовать +/- для языка запросов, но я не вижу преимущества, если вы извлекаете данные из серверной части в браузер, как в большинстве случаев использования JSON. Запросите и отфильтруйте на бэкэнде, чтобы получить как можно меньше нужных данных.

Если по какой-либо причине вам нужно сделать запрос на внешнем интерфейсе (в основном в браузере), то я бы предложил просто использовать array.filter (зачем придумывать что-то еще?).

Тем не менее, я думаю, что более полезным будет API преобразования для json ... они более полезны, поскольку, получив данные, вы можете захотеть их отобразить несколькими способами. Однако, опять же, вы можете сделать многое из этого на сервере (который может быть гораздо легче масштабировать), чем на клиенте - ЕСЛИ вы используете серверную <-> модель клиента.

Просто мои 2 пенса стоит!


1

Проверьте https://github.com/niclasko/Cypher.js (примечание: я автор)

Это реализация Javascript с нулевой зависимостью языка запросов к базе данных графов Cypher вместе с базой данных графов. Он работает в браузере (протестировано с Firefox, Chrome, IE).

С актуальностью к вопросу. Может использоваться для запроса конечных точек JSON:

load json from "http://url/endpoint" as l return l limit 10

Вот пример запроса сложного документа JSON и выполнения анализа на нем:

Пример запроса JSON Cypher.js


1

PythonQL предлагает встроенный синтаксис , который IMHO является улучшением по SQL, в основном потому , что group, window, where, letи т.д. могут быть свободно перемешаны.

$ cat x.py
#coding: pythonql
data = [{"x": 2, "y": 0}, {"x": 3, "y": 1}, {"x": 4, "y": 1}]
q = [x match {'x': as x, 'y': as y} in data where y > 0]
print(sum(q))
print(list(q))

q = [x match {'x': as x, 'y': as y} as d in data where d['y'] > 0]
print(sum(q))

Этот код показывает два разных ответа на ваш вопрос, в зависимости от вашей необходимости обрабатывать всю структуру или только значение. Выполнение дает вам ожидаемый результат.

$ python x.py
7
[3, 4]
7

0

Вы могли бы использовать linq.js.

Это позволяет использовать агрегаты и выборки из набора данных объектов, как данные других структур.

var data = [{ x: 2, y: 0 }, { x: 3, y: 1 }, { x: 4, y: 1 }];

// SUM(X) WHERE Y > 0     -> 7
console.log(Enumerable.From(data).Where("$.y > 0").Sum("$.x"));

// LIST(X) WHERE Y > 0    -> [3, 4]
console.log(Enumerable.From(data).Where("$.y > 0").Select("$.x").ToArray());
<script src="https://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.