Чи існує мова запитів до 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)

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

Будь-які пропозиції?

Редагувати: Це дійсно може бути поганою ідеєю, або JSON може бути занадто загальним форматом для того, про що я думаю. запити динамічно базуються на введенні користувача. Ніби не подобається аргумент, що "нам SQL не потрібен, ми можемо просто записати потрібні нам функції". Зрештою, це або виходить з рук, або ви закінчите писати свою власну версію SQL, коли ви натискаєте її все далі і далі. (Гаразд, я знаю, що це трохи нерозумний аргумент, але ви розумієте.)


У мене є і така потреба. Мені потрібно зіставити вхідні запити JSON за конкретними значеннями у конкретних місцях у дереві об'єктів. Запит повинен бути налаштований користувачем (владою). Поточний спосіб вирішення проблеми полягає в тому, щоб створити XML для переміщення з JSON та застосувати XPath.
Володимир Дюжев

1
Це більше інструмент оболонки, але jq ( stedolan.github.io/jq ) був приголомшливим для вивчення даних json. Спробуйте це на ігровому майданчику: jqplay.org
jtmoulia

Існує веб-інструмент, який дозволяє запускати SQL запити на публічних каналах JSON або API на sqall.co .
Стек чоловік


Відповіді:


91

Звичайно, як щодо:

Вони, здається, трохи працюють, але певною мірою працюють. Вони також схожі на XPath та XQuery концептуально; незважаючи на те, що XML і JSON мають різні концептуальні моделі (ієрархічна проти об'єкта / структура).

EDIT Sep-2015: Насправді існує стандарт JSON Pointer, який дозволяє дуже просто та ефективно переходити вміст JSON. Він не тільки формально визначений, але також підтримується багатьма бібліотеками JSON. Тож я б назвав це фактично справжнім корисним стандартом, хоча через обмежену виразність він може або не може вважатися мовою запиту сам по собі.


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

Якщо говорити про стандарт, я почув слух, що XQuery 3.1 може бути розширений для підтримки запитів JSON (подібно до JSONiq ). Звичайно, це може зайняти деякий час, оскільки XQuery 3.0 ще не офіційно випущений.
Жульєн Рібон

О милосердя, я точно сподіваюся, що ні. Усі бачені у мене XML-> JSON були жахливими помилками - інформаційні моделі несумісні. Але я хотів би бачити JQuery, використовуючи ті самі ідеї, частини синтаксису; просто модифікована відповідно до інформаційної моделі JSON.
StaxMan

1
Для всіх, хто шукає реалізації Ruby JSONPath: 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/ Амазон використовує його в інтерфейсі командного рядка 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}]

SUM (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 застарілими

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


5
array.filter()є частиною JavaScript, а не JSON.
Ієн Самуель Маклін Старший

2
JSON - це підмножина JavaScript, але є багато мов, які підтримують і JSON, і масиви, і в яких реалізований метод фільтрації масивів, тому це дійсна точка.
дакаб


7

ObjectPath - це проста і лігтвайгттна мова запитів для документів JSON складної або невідомої структури. Це схоже на XPath або JSONPath, але набагато потужніше завдяки вбудованим арифметичним розрахункам, механізмам порівняння та вбудованим функціям.

Приклад

Версія Python зріла і використовується у виробництві. JS все ще знаходиться в бета-версії.

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


1
За винятком того, що він майже не має жодної документації, тому важко дізнатися, як зробити що-небудь, як знайти елементи з текстом, як-небудь.
Джеймс О'Брайен

1
@ JamesO'Brien Дякую за ваше зауваження - якщо ви вважаєте, що посилання є марним і маєте на увазі якусь конкретну проблему, повідомте нас про це - хтось спробує допомогти. Зараз ми працюємо над тим, щоб зробити документи більш корисними, я хотів би отримати коментарі.
Ела Беднарек

Спасибі - я ціную це. Я хотів би використати. Наразі я використовую ashphy.com/JSONPathOnlineEvaluator ?
James O'Brien

Не вдалося зрозуміти, як це використовувати в JavaScript через повну відсутність документації.
користувач3670743

Ми шукаємо співробітників, які допоможуть у цьому. Ви можете писати на 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"}

Посилання для пошуку реалізованих посилань працює як у браузері, так і як пакет вузлів npm

npm install searchjs

Він також може робити такі речі, як складні приєднання та заперечення (НЕ). Це споконвічно ігнорує випадок.

Він ще не підсумовує чи не рахує, але це, мабуть, простіше зробити поза межами.


3

Ось кілька простих бібліотек javascript, які також зроблять трюк:

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

  • (додано 2014 р.): інструмент командного рядка jq має акуратний синтаксис, але, на жаль, це бібліотека змінного струму. Приклад використання:

    < 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

Сподіваюся, вам це стане в нагоді ... З повагою


Чи можливо в даний час отримати повний шлях до результатів?
XeniaSis

2
  1. У Google є проект під назвою lovefield ; щойно про це дізналися, і це виглядає цікаво, хоча це більше стосується, ніж просто занижувати підкреслення або подачу.

    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 схожий на вираз Lambda Microsoft для .Net, і він надає подібні можливості запиту колекцій за допомогою синтаксису та функцій предикатів у вигляді SQL. Метою jinqJs є надання подібного досвіду SQL програмістам, знайомим із запитами LINQ.


1

Я по-друге, поняття просто використовувати ваш власний JavaScript, але для чогось більш складного ви можете переглянути дані доджо . Не використовував його, але, схоже, він дає приблизно той тип інтерфейсу запитів, який ви шукаєте.


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 DB або інший тип рідної бази даних). Причина полягає в тому, що запит буде швидше та оптимізованіше.

Я знаю, що 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 та проведення аналізу на ньому:

Приклад запиту Cypher.js JSON


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.