Gibt es eine Abfragesprache für JSON?


227

Gibt es eine (ungefähr) SQL- oder XQuery-ähnliche Sprache zum Abfragen von JSON?

Ich denke an sehr kleine Datensätze, die sich gut für JSON eignen, wo es hilfreich wäre, einfach Fragen wie "Was sind alle Werte von X, wobei Y> 3 ist" zu beantworten oder die üblichen Operationen vom Typ SUM / COUNT auszuführen.

Als komplett erfundenes Beispiel so etwas:

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

Ich denke, dies würde sowohl clientseitig als auch serverseitig funktionieren, wobei die Ergebnisse in die entsprechende sprachspezifische Datenstruktur konvertiert werden (oder möglicherweise als JSON beibehalten werden).

Ein kurzes Googeln deutet darauf hin, dass die Leute darüber nachgedacht und einige Dinge implementiert haben ( JAQL ), aber es scheint noch keine Standardverwendung oder eine Reihe von Bibliotheken entstanden zu sein. Obwohl jede Funktion für sich genommen ziemlich trivial zu implementieren ist, möchte ich das Rad nicht neu erfinden, wenn jemand es bereits richtig gemacht hat.

Irgendwelche Vorschläge?

Bearbeiten: Dies kann in der Tat eine schlechte Idee sein oder JSON kann ein zu allgemeines Format für das sein, was ich denke. Der Grund für den Wunsch nach einer Abfragesprache, anstatt nur die Summierungs- / etc-Funktionen direkt nach Bedarf auszuführen, ist, dass ich hoffe, sie zu erstellen Die Abfragen basieren dynamisch auf Benutzereingaben. Ein bisschen wie das Argument, dass "wir kein SQL brauchen, wir können nur die Funktionen schreiben, die wir brauchen". Irgendwann gerät das entweder außer Kontrolle oder Sie schreiben Ihre eigene SQL-Version, während Sie sie immer weiter vorantreiben. (Okay, ich weiß, das ist ein bisschen albern, aber Sie haben die Idee ..)


Ich habe auch so ein Bedürfnis. Ich muss eingehende JSON-Anforderungen nach bestimmten Werten an bestimmten Stellen im Objektbaum abgleichen. Die Abfrage muss tatsächlich von einem (Haupt-) Benutzer konfiguriert werden. Die aktuelle Problemumgehung besteht darin, aus JSON ein Make-Shift-XML zu erstellen und XPath anzuwenden.
Vladimir Dyuzhev

1
Es ist eher ein Shell-Tool, aber jq ( stedolan.github.io/jq ) war großartig, um json-Daten zu untersuchen. Probieren Sie es auf dem Spielplatz aus: jqplay.org
jtmoulia

Es gibt ein webbasiertes Tool, mit dem Sie SQL-Abfragen in öffentlichen JSON-Feeds oder APIs auf sqall.co ausführen können .
Stack Man


Antworten:


91

Klar, wie wäre es mit:

Sie scheinen alle ein bisschen in Arbeit zu sein, arbeiten aber bis zu einem gewissen Grad. Sie ähneln auch konzeptionell XPath und XQuery. obwohl XML und JSON unterschiedliche konzeptionelle Modelle haben (hierarchisch vs. Objekt / Struktur).

EDIT Sep-2015: Tatsächlich gibt es jetzt den JSON Pointer- Standard, der eine sehr einfache und effiziente Durchquerung von JSON-Inhalten ermöglicht. Es ist nicht nur formal spezifiziert, sondern wird auch von vielen JSON-Bibliotheken unterstützt. Ich würde es also als wirklich nützlichen Standard bezeichnen, obwohl es aufgrund seiner begrenzten Ausdruckskraft per se als Abfragesprache betrachtet werden kann oder nicht.


77
mit anderen Worten, nichts Standard und stabil ... :-(
Vladimir Dyuzhev

Als ich über Standard sprach, hörte ich ein Gerücht, dass XQuery 3.1 erweitert werden könnte, um JSON-Abfragen zu unterstützen (ähnlich wie JSONiq ). Natürlich kann es einige Zeit dauern, da XQuery 3.0 noch nicht offiziell veröffentlicht wurde.
Julien Ribon

Oh Gnade, ich hoffe definitiv nicht. Alle XML-> JSON-Versuche, die ich gesehen habe, waren schreckliche Probleme - Informationsmodelle sind nicht kompatibel. Aber ich würde gerne sehen, dass JQuery dieselben Ideen verwendet, Teile der Syntax; nur richtig auf JSON-Info-Modell geändert.
StaxMan

1
Für alle, die nach einer Ruby-Implementierung von JSONPath suchen: github.com/joshbuddy/jsonpath
Robert Ross

@ GôTô: Wenn Sie diese Freiheit haben, scheint die Verwendung von MongoDB ein praktikabler Ansatz zu sein. (In der Antwort unten finden Sie ein Beispiel für die Übersetzung der Abfrage in die integrierte Shell.)
serv-inc

48

Ich würde mein Projekt mit dem Namen jLinq empfehlen, an dem ich arbeite . Ich bin auf der Suche nach Feedback, daher würde ich gerne hören, was Sie denken.

Wenn Sie Abfragen schreiben können, die denen in LINQ ähneln ...

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

Es ist auch voll erweiterbar!

Die Dokumentation ist noch in Bearbeitung, aber Sie können sie immer noch online ausprobieren.


@hugoware: Gibt es dafür eine Dokumentation? Gibt es andere Abfragen als .starts () (wie enthält?)
Rikki

5
Letztes Update vor 8 Jahren und keine Antwort auf die Frage, ob das Projekt vor 5 Jahren tot ist ... Ich denke, das Projekt ist tot.
CFC


14

jmespath funktioniert wirklich ganz einfach und gut, http://jmespath.org/ Es wird von Amazon in der AWS-Befehlszeilenschnittstelle verwendet, daher muss es ziemlich stabil sein.


5
Gleichzeitig auf derselben Seite: "Wenn Sie erweiterte Funktionen benötigen, die mit --query möglicherweise nicht möglich sind, können Sie jq, einen Befehlszeilen-JSON-Prozessor, ausprobieren." Es scheint also, dass AWS jmespathfür den --queryParameter verwendet, aber jqfür die Befehlszeilen-Weiterleitung empfiehlt . docs.aws.amazon.com/cli/latest/userguide/…
wisbucky

10

jq ist eine J SON q uery-Sprache, die hauptsächlich für die Befehlszeile gedacht ist, jedoch an eine Vielzahl von Programmiersprachen (Java, node.js, php, ...) gebunden ist und sogar über jq-web im Browser verfügbar ist .

Hier sind einige Abbildungen, die auf der ursprünglichen Frage basieren, die diesen JSON als Beispiel gegeben hat:

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

SUMME (X) WO Y> 0 (würde 7 entsprechen)

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

LISTE (X) WO Y> 0 (würde [3,4] entsprechen)

map(.y > 0)

Die jq-Syntax erweitert die JSON-Syntax

Jeder JSON-Ausdruck ist ein gültiger jq-Ausdruck, und Ausdrücke wie [1, (1+1)]und {"a": (1 + 1)} `veranschaulichen, wie jq die JSON-Syntax erweitert.

Ein nützlicheres Beispiel ist der Ausdruck jq:

{a,b}

die, angesichts der JSON Wert {"a":1, "b":2, "c": 3}, ausgewertet {"a":1, "b":2}.


8

Die integrierte array.filter()Methode macht die meisten dieser sogenannten Javascript-Abfragebibliotheken überflüssig

Sie können so viele Bedingungen in den Delegaten einfügen, wie Sie sich vorstellen können: einfacher Vergleich, Start mit usw. Ich habe nicht getestet, aber Sie könnten wahrscheinlich auch Filter verschachteln, um innere Sammlungen abzufragen.


5
array.filter()ist Teil von JavaScript, nicht von JSON.
Iain Samuel McLean Elder

2
JSON ist eine Teilmenge von JavaScript, aber es gibt viele Sprachen, die sowohl JSON als auch Arrays unterstützen und in denen eine Array-Filtermethode implementiert ist. Dies ist also ein gültiger Punkt.
Dakab


7

ObjectPath ist eine einfache und leichtgewichtige Abfragesprache für JSON-Dokumente mit komplexer oder unbekannter Struktur. Es ähnelt XPath oder JSONPath, ist jedoch dank eingebetteter arithmetischer Berechnungen, Vergleichsmechanismen und integrierter Funktionen viel leistungsfähiger.

Beispiel

Die Python-Version ist ausgereift und wird in der Produktion verwendet. JS ist noch in der Beta.

Wahrscheinlich werden wir in naher Zukunft eine vollwertige Javascript-Version bereitstellen. Wir möchten es auch weiterentwickeln, damit es als einfachere Alternative zu Mongo-Abfragen dienen kann.


1
Abgesehen davon, dass es kaum Dokumentation gibt, ist es schwierig herauszufinden, wie man so etwas wie Elemente mit Text wie etwas findet.
James O'Brien

1
@ JamesO'Brien Vielen Dank für Ihre Bemerkung - wenn Sie die Referenz unbrauchbar finden und ein bestimmtes Problem haben, lassen Sie es uns hier wissen - jemand wird versuchen zu helfen. Wir arbeiten derzeit daran, die Dokumente benutzerfreundlicher zu machen. Ich würde mich über Ihre Kommentare freuen.
Ela Bednarek

Danke ich schätze das. Ich würde gerne verwenden. Derzeit verwende ich ashphy.com/JSONPathOnlineEvaluator ?
James O'Brien

Konnte nicht herausfinden, wie dies mit Javascript verwendet werden soll, da es an Dokumentation mangelt.
user3670743

Wir suchen Mitarbeiter, die uns dabei helfen. Sie können auf Github oder Google Groups Groups.google.com/forum/#!members/objectpath schreiben, was Sie erreichen möchten , und ich bin sicher, dass jemand Ihre Fragen beantworten wird.
Ela Bednarek


4

OK, dieser Beitrag ist etwas alt, aber ... wenn Sie eine SQL-ähnliche Abfrage in nativem JSON (oder JS-Objekten) für JS-Objekte durchführen möchten, schauen Sie unter https://github.com/deitch/searchjs nach

Es ist sowohl eine vollständig in JSON geschriebene jsql-Sprache als auch eine Referenzimplementierung. Sie können sagen: "Ich möchte alle Objekte in einem Array finden, die den Namen ===" John "&& age === 25 haben als:

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

Die Referenzimplementierung searchjs funktioniert sowohl im Browser als auch als Node-Npm-Paket

npm install searchjs

Es kann auch komplexe Verknüpfungen und Negationen ausführen (NICHT). Der Fall wird von Haus aus ignoriert.

Es wird noch nicht summiert oder gezählt, aber es ist wahrscheinlich einfacher, diese draußen zu machen.


3

Hier sind einige einfache Javascript-Bibliotheken, die ebenfalls den Trick machen:

  • Dollar Q ist eine schöne, leichte Bibliothek. Es hat ein vertrautes Gefühl in der Verkettungssyntax, die von jQuery populär gemacht wurde, und ist nur 373 SLOC.
  • SpahQL ist eine voll funktionsfähige Abfragesprache mit einer ähnlichen Syntax wie XPath ( Homepage , Github
  • jFunk ist eine in Bearbeitung befindliche Abfragesprache mit einer ähnlichen Syntax wie CSS / jQuery-Selektoren. Es sah vielversprechend aus, hatte aber keine Entwicklung, die über das ursprüngliche Engagement hinausging.

  • (hinzugefügt 2014): Das Befehlszeilentool jq hat eine ordentliche Syntax, ist aber leider eine AC-Bibliothek. Anwendungsbeispiel:

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


3

In MongoDB würde dies so funktionieren (in der Mongo-Shell gibt es Treiber für eine Sprache Ihrer Wahl).

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

Die ersten drei Befehle fügen die Daten in Ihre Sammlung ein. (Starten Sie einfach diemongod Server und stellen Sie eine Verbindung mit dem mongoClient her.)

Die nächsten beiden verarbeiten die Daten. $matchFilter, $groupgilt sumund list, respectively.


2

SpahQL ist das vielversprechendste und durchdachteste davon, soweit ich das beurteilen kann. Ich kann es nur empfehlen.


2


Ich habe gerade eine freigebbare Version einer clientseitigen JS-lib (defiant.js) fertiggestellt, die genau das tut, wonach Sie suchen. Mit defiant.js können Sie eine JSON-Struktur mit den Ihnen bekannten XPath-Ausdrücken abfragen (keine neuen Syntaxausdrücke wie in JSONPath).

Beispiel für die Funktionsweise (siehe Browser hier 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

Wie Sie sehen können, erweitert DefiantJS das globale Objekt JSON um eine Suchfunktion, und das zurückgegebene Array wird mit Aggregatfunktionen geliefert. DefiantJS enthält einige andere Funktionen, die jedoch für dieses Thema nicht relevant sind. Wie auch immer, Sie können die Bibliothek mit einem clientseitigen XPath-Evaluator testen. Ich denke, Leute, die nicht mit XPath vertraut sind, werden diesen Evaluator nützlich finden.
http://defiantjs.com/#xpath_evaluator

Weitere Informationen zu defiant.js
http://defiantjs.com/
https://github.com/hbi99/defiant.js

Ich hoffe, Sie finden es nützlich ... Grüße


Ist es derzeit möglich, den vollständigen Pfad zu den Ergebnissen zu erhalten?
XeniaSis

2
  1. Google hat ein Projekt namens Lovefield ; Ich habe es gerade herausgefunden und es sieht interessant aus, obwohl es mehr damit zu tun hat, als nur Unterstrich oder Lodash zu verwenden.

    https://github.com/google/lovefield

Lovefield ist eine relationale Abfrage-Engine, die in reinem JavaScript geschrieben ist. Es bietet auch Hilfe beim Speichern von Daten auf der Browserseite, z. B. mithilfe von IndexedDB zum lokalen Speichern von Daten. Es bietet SQL-ähnliche Syntax und funktioniert browserübergreifend (unterstützt derzeit Chrome 37+, Firefox 31+, IE 10+ und Safari 5.1 + ...


  1. Ein weiterer interessanter neuer Eintrag in diesem Bereich namens jinqJs .

    http://www.jinqjs.com/

    Wenn Sie die Beispiele kurz betrachten , sieht es vielversprechend aus, und das API-Dokument scheint gut geschrieben zu sein.


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 ist eine kleine, einfache, leichte und erweiterbare JavaScript-Bibliothek, die keine Abhängigkeiten aufweist. jinqJs bietet eine einfache Möglichkeit, SQL-ähnliche Abfragen für JavaScript-Arrays, Sammlungen und Webdienste durchzuführen, die eine JSON-Antwort zurückgeben. jinqJs ähnelt dem Lambda-Ausdruck von Microsoft für .Net und bietet ähnliche Funktionen wie Abfragesammlungen, die eine SQL-ähnliche Syntax und Prädikatfunktionalität verwenden. Der Zweck von jinqJs besteht darin, Programmierern, die mit LINQ-Abfragen vertraut sind, eine SQL-ähnliche Erfahrung zu bieten.


1

Ich werde mich dem Gedanken anschließen, nur Ihr eigenes Javascript zu verwenden, aber für etwas Anspruchsvolleres könnten Sie sich Dojo-Daten ansehen . Ich habe es nicht verwendet, aber es sieht so aus, als ob es Ihnen ungefähr die Art von Abfrageoberfläche bietet, nach der Sie suchen.


1

Die aktuelle Jaql-Implementierung zielt auf die Verarbeitung großer Datenmengen mithilfe eines Hadoop-Clusters ab. Daher ist dies möglicherweise mehr als erforderlich. Es läuft jedoch problemlos ohne einen Hadoop-Cluster (erfordert jedoch weiterhin den Hadoop-Code und seine Abhängigkeiten, um kompiliert zu werden, die meistens enthalten sind). Eine kleine Implementierung von Jaql, die in Javascript und einen Browser eingebettet werden könnte, wäre eine großartige Ergänzung des Projekts.

Ihre obigen Beispiele lassen sich leicht in Jaql schreiben:

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

Natürlich gibt es noch viel mehr. Beispielsweise:

// 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 kann unter http://code.google.com/p/jaql/ heruntergeladen / diskutiert werden.


1

Sie können auch Underscore.js verwenden , eine Bibliothek mit Schweizer Messern, um Sammlungen zu bearbeiten. Mit _.filter, _.pluck, _.reducekönnen Sie tun , SQL-ähnliche Abfragen.

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 funktioniert sowohl clientseitig als auch serverseitig und ist eine bemerkenswerte Bibliothek.

Sie können auch Lo-Dash verwenden , eine Abzweigung von Underscore.js mit besseren Leistungen.


1

Wann immer möglich, würde ich die gesamte Abfrage auf das Backend auf dem Server verlagern (auf die SQL-Datenbank oder einen anderen nativen Datenbanktyp). Grund dafür ist, dass die Abfrage schneller und optimierter durchgeführt werden kann.

Ich weiß, dass jSON eigenständig sein kann und es möglicherweise +/- für eine Abfragesprache gibt, aber ich kann den Vorteil nicht erkennen, wenn Sie Daten aus dem Backend in einen Browser abrufen, wie die meisten JSON-Anwendungsfälle. Fragen Sie das Backend ab und filtern Sie es, um die benötigten Daten so klein wie möglich zu halten.

Wenn Sie aus irgendeinem Grund im Front-End abfragen müssen (meistens in einem Browser), würde ich vorschlagen, nur array.filter zu verwenden (warum etwas anderes erfinden?).

Das heißt, was ich für nützlicher halte, ist eine Transformations-API für json ... sie sind nützlicher, da Sie die Daten, sobald Sie sie haben, möglicherweise auf verschiedene Arten anzeigen möchten. Sie können jedoch wieder viel davon auf dem Server tun (was viel einfacher zu skalieren sein kann) als auf dem Client - WENN Sie das Server-Client-Modell verwenden.

Nur meine 2 Pence wert!


1

Überprüfen Sie https://github.com/niclasko/Cypher.js (Hinweis: Ich bin der Autor)

Es handelt sich um eine Javascript-Implementierung ohne Abhängigkeit der Abfragesprache der Cypher-Diagrammdatenbank zusammen mit einer Diagrammdatenbank. Es läuft im Browser (getestet mit Firefox, Chrome, IE).

Mit Relevanz für die Frage. Es kann zum Abfragen von JSON-Endpunkten verwendet werden:

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

Hier ist ein Beispiel für das Abfragen eines komplexen JSON-Dokuments und dessen Analyse:

Beispiel für eine JSON-Abfrage von Cypher.js


1

PythonQL bietet eine eingebettete Syntax , dass IMHO eine Verbesserung auf SQL ist, vor allem , weil group, window, where, let, etc. können frei miteinander vermischt werden.

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

Dieser Code zeigt zwei verschiedene Antworten auf Ihre Frage, je nachdem, ob Sie die gesamte Struktur oder nur den Wert bearbeiten müssen. Die Ausführung gibt Ihnen das erwartete Ergebnis.

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

0

Du könntest benutzen linq.js .

Dies ermöglicht die Verwendung von Aggregationen und Auswahlen aus einem Datensatz von Objekten als Daten anderer Strukturen.

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>

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.