Czy istnieje język zapytań dla JSON?


227

Czy istnieje (w przybliżeniu) język SQL lub XQuery podobny do zapytania JSON?

Myślę o bardzo małych zestawach danych, które ładnie odwzorowują na JSON, w których miło byłoby łatwo odpowiedzieć na zapytania, takie jak „jakie są wszystkie wartości X, gdzie Y> 3” lub wykonać zwykłe operacje typu SUMA / LICZBA.

Jako całkowicie wymyślony przykład, coś takiego:

[{"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])

Myślę, że działałoby to zarówno po stronie klienta, jak i po stronie serwera, a wyniki były konwertowane do odpowiedniej struktury danych specyficznej dla języka (lub być może przechowywane jako JSON)

Szybki Googling sugeruje, że ludzie pomyśleli o tym i wdrożyli kilka rzeczy ( JAQL ), ale nie wydaje się, aby pojawiło się jeszcze standardowe użycie lub zestaw bibliotek. Chociaż każda funkcja jest dość trywialna do samodzielnego wdrożenia, jeśli ktoś już to zrobił poprawnie, nie chcę ponownie wymyślać koła.

Jakieś sugestie?

Edycja: To może być zły pomysł lub JSON może być zbyt ogólnym formatem do tego, co myślę. Powodem, dla którego chcę języka zapytań zamiast po prostu wykonywania funkcji sumowania / etc bezpośrednio w razie potrzeby, jest to, że mam nadzieję zbudować zapytania dynamicznie oparte na danych wprowadzanych przez użytkownika. Niby argument, że „nie potrzebujemy SQL, możemy po prostu napisać potrzebne funkcje”. W końcu to wymyka się spod kontroli lub kończy się pisanie własnej wersji języka SQL, gdy idzie się o krok dalej. (Okej, wiem, że to trochę głupiutki argument, ale masz pomysł ...)


Ja też mam taką potrzebę. Muszę dopasować przychodzące żądania JSON według określonych wartości w określonych lokalizacjach w drzewie obiektów. Zapytanie musi być skonfigurowane przez (zaawansowanego) użytkownika. Obecnym obejściem jest zbudowanie make-shift XML z JSON i zastosowanie XPath.
Vladimir Dyuzhev

1
To bardziej narzędzie powłoki, ale jq ( stedolan.github.io/jq ) jest świetny do eksploracji danych json. Wypróbuj na placu zabaw: jqplay.org
jtmoulia

Istnieje narzędzie internetowe, które umożliwia uruchamianie zapytań SQL w publicznych kanałach JSON lub interfejsach API w sqall.co .
Stack Man


Odpowiedzi:


91

Jasne, a może:

Wszystkie wydają się być w toku, ale do pewnego stopnia działają. Są one również podobne do XPath i XQuery pod względem koncepcyjnym; mimo że XML i JSON mają różne modele pojęciowe (hierarchiczne vs obiekt / struktura).

EDYCJA września 2015: W rzeczywistości istnieje teraz standard JSON Pointer, który umożliwia bardzo proste i wydajne przechodzenie zawartości JSON. Jest nie tylko formalnie określony, ale także obsługiwany przez wiele bibliotek JSON. Nazwałbym go więc rzeczywistym, użytecznym standardem, chociaż ze względu na jego ograniczoną ekspresyjność może, ale nie musi, być uważany za język zapytań per se.


77
innymi słowy, nic standardowego i stabilnego ... :-(
Vladimir Dyuzhev

Mówiąc o standardzie, usłyszałem pogłoskę, że XQuery 3.1 może zostać rozszerzony o obsługę zapytań JSON (podobnie jak JSONiq ). Oczywiście może minąć trochę czasu, ponieważ XQuery 3.0 nie jest jeszcze oficjalnie wydany.
Julien Ribon,

O litość, zdecydowanie mam nadzieję, że nie. Wszystkie próby XML-> JSON, które widziałem, były okropnymi komunikatami - modele informacyjne są niezgodne. Ale chciałbym, aby JQuery korzystał z tych samych pomysłów, części składni; właśnie poprawnie zmodyfikowano do modelu informacyjnego JSON.
StaxMan,

1
Dla każdego, kto szuka implementacji języka JSONPath w języku Ruby: github.com/joshbuddy/jsonpath
Robert Ross

@ GôTô: Używanie MongoDB, jeśli masz tę swobodę, wydaje się realnym podejściem. (patrz odpowiedź poniżej, aby przetłumaczyć zapytanie na wbudowaną powłokę)
serv-inc

48

Poleciłbym mój projekt, nad którym pracuję, o nazwie jLinq . Szukam opinii, więc chciałbym usłyszeć, co myślisz.

Jeśli pozwala na pisanie zapytań podobnych do tego w 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)
        };
    });

Jest również w pełni rozszerzalny!

Dokumentacja jest wciąż w toku, ale nadal możesz spróbować w Internecie.


@hugoware: czy jest na to jakaś dokumentacja. Czy są jakieś zapytania inne niż .starts () (takie jak zawiera?)
Rikki,

5
Ostatnia aktualizacja 8 lat temu i brak odpowiedzi na pytanie, czy projekt jest martwy 5 lat temu ... Myślę, że projekt jest martwy.
por.


14

jmespath działa naprawdę dość łatwo i dobrze, http://jmespath.org/ Jest używany przez Amazon w interfejsie wiersza poleceń AWS, więc musi być całkiem stabilny.


5
Ale jednocześnie na tej samej stronie: „Jeśli potrzebujesz bardziej zaawansowanych funkcji, które mogą nie być możliwe przy użyciu --query, możesz sprawdzić jq, procesor JSON wiersza poleceń.” Wygląda więc na to, że AWS używa jmespathtego --queryparametru, ale zaleca się jqdla potoków wiersza poleceń. docs.aws.amazon.com/cli/latest/userguide/…
wisbucky

10

jq jest J SON q język uery przeznaczony głównie do linii poleceń, ale z powiązaniami do szerokiej gamy języków programowania (Java, node.js, php, ...) i nawet dostępnych w przeglądarce poprzez JQ-web .

Oto kilka ilustracji opartych na oryginalnym pytaniu, które podało ten JSON jako przykład:

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

SUMA (X) GDZIE Y> 0 (odpowiada 7)

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

LISTA (X) GDZIE Y> 0 (odpowiada [3,4])

map(.y > 0)

Składnia jq rozszerza składnię JSON

Każde wyrażenie JSON jest prawidłowym wyrażeniem jq i wyrażeniami takimi jak [1, (1+1)] i {"a": (1 + 1)} `pokazują, jak jq rozszerza składnię JSON.

Bardziej przydatnym przykładem jest wyrażenie jq:

{a,b}

który, biorąc pod uwagę wartość JSON {"a":1, "b":2, "c": 3}, ocenia na {"a":1, "b":2}.


8

Wbudowana array.filter()metoda powoduje, że większość tak zwanych bibliotek zapytań javascript staje się przestarzała

Możesz umieścić w delegacie tyle warunków, ile możesz sobie wyobrazić: proste porównanie, startWith itp. Nie testowałem, ale prawdopodobnie możesz również zagnieżdżać filtry do odpytywania wewnętrznych kolekcji.


5
array.filter()jest częścią JavaScript, a nie JSON.
Iain Samuel McLean Starszy

2
JSON jest podzbiorem JavaScript, ale istnieje wiele języków, które obsługują zarówno JSON, jak i tablice i które mają zaimplementowaną metodę filtrowania tablic, więc jest to poprawny punkt.
dakab

7

Jeśli używasz platformy .NET, Json.NET obsługuje zapytania LINQ ponad JSON. Ten post zawiera kilka przykładów. Obsługuje filtrowanie, mapowanie, grupowanie itp.


7

ObjectPath jest prostym językiem zapytań dla dokumentów JSON o złożonej lub nieznanej strukturze. Jest podobny do XPath lub JSONPath, ale o wiele bardziej wydajny dzięki wbudowanym obliczeniom arytmetycznym, mechanizmom porównywania i wbudowanym funkcjom.

Przykład

Wersja Python jest dojrzała i używana w produkcji. JS jest wciąż w fazie beta.

Prawdopodobnie w najbliższej przyszłości zapewnimy pełną wersję Javascript. Chcemy również dalej go rozwijać, aby mógł służyć jako prostsza alternatywa dla zapytań Mongo.


1
Tyle, że nie ma prawie żadnej dokumentacji, więc trudno jest dowiedzieć się, jak zrobić coś takiego, jak znaleźć elementy z tekstem jak coś.
James O'Brien

1
@ JamesO'Brien Dziękujemy za uwagę - jeśli uznasz odniesienie za bezużyteczne i masz na myśli jakiś konkretny problem, daj nam znać tutaj - ktoś spróbuje ci pomóc. Obecnie pracujemy nad zwiększeniem użyteczności dokumentów. Chciałbym, aby Twoje komentarze.
Ela Bednarek

Dzięki doceniam to. Chciałbym użyć. Obecnie używam ashphy.com/JSONPathOnlineEvaluator ?
James O'Brien

Nie mogłem wymyślić, jak tego używać z Javascriptem z powodu całkowitego braku dokumentacji.
user3670743

Szukamy współpracowników, którzy pomogą w tym. Możesz pisać na Github lub w Google groups groups.google.com/forum/#!members/objectpath, co próbujesz osiągnąć, i jestem pewien, że ktoś odpowie na twoje pytania.
Ela Bednarek

6

Innym sposobem, aby na to spojrzeć, jest użycie mongoDB Możesz przechowywać JSON w mongo, a następnie wykonać zapytanie za pomocą składni zapytania mongodb.


MongoDB jest bardzo przyjemny w użyciu. Zobacz odpowiedź poniżej, aby zapoznać się z przykładem użycia.
serv-inc

4

OK, ten post jest trochę stary, ale ... jeśli chcesz wykonać zapytanie podobne do SQL w natywnym JSON (lub obiektach JS) na obiektach JS, spójrz na https://github.com/deitch/searchjs

Jest to zarówno język jsql napisany całkowicie w JSON, jak i implementacja referencyjna. Możesz powiedzieć: „Chcę znaleźć cały obiekt w tablicy o nazwie ===„ John ”&& age === 25 jako:

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

Searchjs implementacji referencyjnej działa zarówno w przeglądarce, jak i jako pakiet npm węzła

npm install searchjs

Może także wykonywać takie czynności, jak złożone sprzężenia i negacja (NIE). Natywnie ignoruje wielkość liter.

Nie robi jeszcze sumowania ani się nie liczy, ale prawdopodobnie łatwiej jest robić to na zewnątrz.


3

Oto kilka prostych bibliotek javascript, które również wykonają tę sztuczkę:

  • Dollar Q to niezła lekka biblioteka. Ma znajomą składnię łańcuchową popularną przez jQuery i ma tylko 373 SLOC.
  • SpahQL to w pełni funkcjonalny język zapytań o składni podobnej do XPath ( Homepage , Github
  • jFunk to język zapytań w toku, o składni podobnej do selektorów CSS / jQuery. Wyglądało to obiecująco, ale nie miało żadnego rozwoju poza początkowym zatwierdzeniem.

  • (dodano 2014): narzędzie wiersza polecenia jq ma zgrabną składnię, ale niestety jest to biblioteka ac. Przykładowe użycie:

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


3

W MongoDB tak to by działało (w powłoce mongo istnieją sterowniki dla wybranego języka).

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"}}}]);

Pierwsze trzy polecenia wstawiają dane do Twojej kolekcji. (Wystarczy uruchomić mongodserwer i połączyć się z mongoklientem).

Następne dwa przetwarzają dane. $matchfiltry, $groupstosuje odpowiednio sumi list.


2

O ile wiem, SpahQL jest najbardziej obiecującą i przemyślaną z nich. Bardzo polecam to sprawdzić.


2


Właśnie skończyłem wydaną wersję JS-lib po stronie klienta (defiant.js), która robi to, czego szukasz. Za pomocą defiant.js można wyszukiwać w strukturze JSON za pomocą znanych Ci wyrażeń XPath (bez nowych wyrażeń składniowych jak w JSONPath).

Przykład tego, jak to działa (zobacz w przeglądarce tutaj 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

Jak widać, DefiantJS rozszerza globalny obiekt JSON o funkcję wyszukiwania, a zwrócona tablica jest dostarczana z funkcjami agregującymi. DefiantJS zawiera kilka innych funkcji, ale są one poza zakresem tego tematu. W każdym razie możesz przetestować bibliotekę za pomocą narzędzia XPath Evaluator. Myślę, że ludzie, którzy nie znają XPath, uznają to za przydatne.
http://defiantjs.com/#xpath_evaluator

Więcej informacji o defiant.js
http://defiantjs.com/
https://github.com/hbi99/defiant.js

Mam nadzieję, że okaże się przydatny ... Pozdrawiam


Czy obecnie można uzyskać pełną ścieżkę do wyników?
XeniaSis,

2
  1. Google ma projekt o nazwie lovefield ; właśnie się o tym dowiedziałem i wygląda interesująco, choć jest bardziej zaangażowany niż zwykłe dodawanie podkreślenia lub lodash.

    https://github.com/google/lovefield

Lovefield to relacyjny silnik zapytań napisany w czystym JavaScript. Zapewnia również pomoc w utrzymywaniu danych po stronie przeglądarki, np. Przy użyciu IndexedDB do lokalnego przechowywania danych. Zapewnia składnię podobną do SQL i działa w różnych przeglądarkach (obecnie obsługuje Chrome 37+, Firefox 31+, IE 10+ i Safari 5.1 + ...


  1. Kolejny interesujący ostatni wpis w tej przestrzeni o nazwie jinqJs .

    http://www.jinqjs.com/

    Krótko przeglądając przykłady , wygląda obiecująco, a dokument API wydaje się być dobrze napisany.


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 to mała, prosta, lekka i rozszerzalna biblioteka javaScript, która nie ma żadnych zależności. jinqJs zapewnia prosty sposób wykonywania zapytań typu SQL na tablicach javaScript, kolekcjach i usługach internetowych, które zwracają odpowiedź JSON. jinqJs jest podobny do wyrażenia Lambda Microsoftu dla .Net i zapewnia podobne możliwości wyszukiwania kolekcji przy użyciu składni podobnej do SQL i funkcjonalności predykatów. Celem jinqJs jest zapewnienie podobnego do SQL doświadczenia dla programistów znających zapytania LINQ.


1

Będę popierać pojęcie używania własnego javascript, ale dla czegoś bardziej wyrafinowanego możesz spojrzeć na dane dojo . Nie korzystałem z niego, ale wygląda na to, że daje z grubsza rodzaj interfejsu zapytań, którego szukasz.


1

Obecna implementacja Jaql jest ukierunkowana na przetwarzanie dużych danych za pomocą klastra Hadoop, więc może być więcej niż potrzebujesz. Działa jednak łatwo bez klastra Hadoop (ale nadal wymaga kodu Hadoop i jego zależności do skompilowania, które są w większości uwzględnione). Niewielka implementacja Jaql, która mogłaby być osadzona w JavaScript i przeglądarce, byłaby świetnym dodatkiem do projektu.

Powyższe przykłady można łatwo napisać w języku 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]

Oczywiście jest o wiele więcej. Na przykład:

// 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 można pobrać / omówić na stronie http://code.google.com/p/jaql/


1

Możesz także użyć Underscore.js, który jest w zasadzie biblioteką szwajcarskiego noża do manipulowania kolekcjami. Za pomocą _.filter,_.pluck , _.reducemożna zrobić SQL-like zapytaniami.

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 działa zarówno po stronie klienta, jak i serwera i jest znaczącą biblioteką.

Możesz także użyć Lo-Dash, który jest rozwidleniem Underscore.js o lepszych osiągach.


1

Ilekroć jest to możliwe, przenoszę wszystkie zapytania do zaplecza na serwerze (do SQL DB lub innego rodzimego typu bazy danych). Powodem jest to, że będzie ono szybsze i bardziej zoptymalizowane do wykonywania zapytań.

Wiem, że jSON może być samodzielny i może istnieć +/- za język zapytań, ale nie widzę korzyści, jeśli pobierasz dane z backendu do przeglądarki, ponieważ większość przypadków użycia JSON. Zapytaj i przefiltruj na zapleczu, aby uzyskać jak najmniej potrzebnych danych.

Jeśli z jakiegokolwiek powodu potrzebujesz zapytań na interfejsie (głównie w przeglądarce), sugerowałbym użycie array.filter (po co wymyślać coś innego?).

To powiedziawszy, to, co moim zdaniem byłoby bardziej użyteczne, to API transformacji dla json ... są one bardziej przydatne, ponieważ kiedy już masz dane, możesz chcieć je wyświetlić na wiele sposobów. Jednak znowu możesz zrobić wiele z tego na serwerze (co może być znacznie łatwiejsze do skalowania) niż na kliencie - JEŻELI używasz modelu serwera <--> klienta.

Tylko moje 2 pensy warte!


1

Sprawdź https://github.com/niclasko/Cypher.js (uwaga: jestem autorem)

Jest to implementacja JavaScript języka zapytań bazy danych wykresów Cypher w zerowej zależności oraz baza danych grafów. Działa w przeglądarce (testowana z Firefox, Chrome, IE).

Z odniesieniem do pytania. Można go użyć do zapytania o punkty końcowe JSON:

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

Oto przykład zapytania do złożonego dokumentu JSON i wykonania na nim analizy:

Przykład zapytania Cypher.js JSON


1

PythonQL oferuje wbudowany składni że IMHO jest poprawa na SQL, głównie dlatego group, window, where, let, itd. Mogą być dowolnie mieszane.

$ 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))

Ten kod pokazuje dwie różne odpowiedzi na twoje pytanie, w zależności od potrzeby obsługi całej struktury lub tylko wartości. Wykonanie daje oczekiwany wynik.

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

0

Możesz użyć linq.js.

Pozwala to na użycie agregacji i wyborów z zestawu danych obiektów, podobnie jak innych danych struktur.

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>

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.