Esiste un linguaggio di query per JSON?


227

Esiste un linguaggio (approssimativamente) simile a SQL o XQuery per l'interrogazione di JSON?

Sto pensando a set di dati molto piccoli che si associano perfettamente a JSON dove sarebbe bello rispondere facilmente a domande come "quali sono tutti i valori di X dove Y> 3" o fare le solite operazioni di tipo SUM / COUNT.

Come esempio completamente inventato, qualcosa del genere:

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

Sto pensando che funzionerebbe sia sul lato client che sul lato server con i risultati convertiti nella struttura dati specifica della lingua appropriata (o forse mantenuti come JSON)

Un rapido googling suggerisce che le persone ci hanno pensato e implementato alcune cose ( JAQL ), ma non sembra che sia ancora emerso un uso standard o un set di librerie. Mentre ogni funzione è abbastanza banale da implementare da sola, se qualcuno l'ha già fatto bene non voglio reinventare la ruota.

Eventuali suggerimenti?

Modifica: questa potrebbe davvero essere una cattiva idea o JSON potrebbe essere un formato troppo generico per quello che sto pensando. le query basate dinamicamente sull'input dell'utente. Mi piace l'argomento secondo cui "non abbiamo bisogno di SQL, possiamo semplicemente scrivere le funzioni di cui abbiamo bisogno". Alla fine o ti sfugge di mano o finisci per scrivere la tua versione di SQL mentre la spingi sempre più avanti. (Va bene, lo so che è un po 'una sciocca discussione, ma hai l'idea ..)


Anch'io ho un tale bisogno. Devo abbinare le richieste JSON in arrivo in base a valori specifici in posizioni specifiche nella struttura degli oggetti. La query deve effettivamente essere configurata da un utente (di potenza). L'attuale soluzione alternativa è creare un XML make-shift da JSON e applicare XPath.
Vladimir Dyuzhev,

1
È più uno strumento shell, ma jq ( stedolan.github.io/jq ) è stato fantastico per esplorare i dati json. Provalo nel parco giochi: jqplay.org
jtmoulia,

Esiste uno strumento basato sul Web che consente di eseguire query SQL su feed JSON pubblici o API su sqall.co .
Stack Man


Risposte:


91

Certo, che ne dici di:

Sembrano tutti essere un po 'in corso di elaborazione, ma funzionano in una certa misura. Sono anche simili a XPath e XQuery concettualmente; anche se XML e JSON hanno modelli concettuali diversi (gerarchico vs oggetto / struttura).

EDIT settembre 2015: attualmente esiste lo standard JSON Pointer che consente un attraversamento molto semplice ed efficiente del contenuto JSON. Non è solo formalmente specificato, ma è anche supportato da molte librerie JSON. Quindi lo definirei un vero standard utile reale, sebbene a causa della sua espressività limitata possa o meno essere considerato il linguaggio di query in sé.


77
in altre parole, niente di standard e stabile ... :-(
Vladimir Dyuzhev,

Parlando di standard, ho sentito una voce secondo cui XQuery 3.1 potrebbe essere esteso per supportare le query JSON (simile a JSONiq ). Certo, potrebbe volerci del tempo poiché XQuery 3.0 non è ancora ufficialmente rilasciato.
Julien Ribon,

Oh, pietà, spero proprio di no. Tutti i tentativi XML-> JSON che ho visto sono stati disastri orribili - i modelli di informazioni sono incompatibili. Ma vorrei vedere JQuery usando le stesse idee, parti di sintassi; appena modificato correttamente nel modello informativo JSON.
StaxMan,

1
Per tutti coloro che cercano un'implementazione Ruby di JSONPath: github.com/joshbuddy/jsonpath
Robert Ross,

@ GôTô: usare MongoDB, se hai quella libertà, sembra un approccio praticabile. (vedere la risposta di seguito per un esempio di come tradurre la query nella shell integrata)
serv-inc

48

Consiglierei il mio progetto a cui sto lavorando chiamato jLinq . Sto cercando feedback, quindi sarei interessato a sentire cosa ne pensi.

Se ti consente di scrivere query simili a come faresti in 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)
        };
    });

È anche completamente estensibile!

La documentazione è ancora in corso, ma puoi ancora provarla online.


@hugoware: c'è qualche documentazione per questo. Ci sono domande diverse da .start () (come contiene?)
Rikki,

5
Ultimo aggiornamento 8 anni fa e nessuna risposta alla domanda se il progetto è morto 5 anni fa ... Penso che il progetto sia morto.
cfr


14

jmespath funziona davvero abbastanza facilmente e bene, http://jmespath.org/ Viene utilizzato da Amazon nell'interfaccia della riga di comando di AWS, quindi deve essere abbastanza stabile.


5
Eppure allo stesso tempo sulla stessa pagina: "Se hai bisogno di funzionalità più avanzate che potrebbero non essere possibili con --query, puoi dare un'occhiata a jq, un processore JSON da riga di comando". Quindi sembra che AWS utilizzi jmespathper il --queryparametro, ma consiglia jqper le tubazioni della riga di comando. docs.aws.amazon.com/cli/latest/userguide/…
wisbucky

10

jq è un linguaggio J SON q uery, principalmente destinato alla riga di comando ma con collegamenti a una vasta gamma di linguaggi di programmazione (Java, node.js, php, ...) e persino disponibile nel browser tramite jq-web .

Ecco alcune illustrazioni basate sulla domanda originale, che ha fornito questo JSON come esempio:

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

SOMMA (X) DOVE Y> 0 (equivarrebbe a 7)

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

ELENCO (X) DOVE Y> 0 (equivarrebbe a [3,4])

map(.y > 0)

La sintassi jq estende la sintassi JSON

Ogni espressione JSON è un'espressione jq valida ed espressioni come [1, (1+1)]e {"a": (1 + 1)} `illustrano come jq estende la sintassi JSON.

Un esempio più utile è l'espressione jq:

{a,b}

che, dato il valore JSON {"a":1, "b":2, "c": 3}, valuta {"a":1, "b":2}.


8

Il array.filter()metodo integrato rende obsolete la maggior parte di queste cosiddette librerie di query javascript

Puoi inserire tutte le condizioni all'interno del delegato che puoi immaginare: un semplice confronto, inizia con, ecc. Non ho ancora testato, ma probabilmente potresti anche annidare i filtri per interrogare le raccolte interne.


5
array.filter()fa parte di JavaScript, non di JSON.
Iain Samuel McLean Elder,

2
JSON è un sottoinsieme di JavaScript, ma ci sono molte lingue che supportano sia JSON che array e che hanno implementato un metodo di filtro array, quindi questo è un punto valido.
Dakab,

7

Se si utilizza .NET, Json.NET supporta le query LINQ nella parte superiore di JSON. Questo post ha alcuni esempi. Supporta filtro, mappatura, raggruppamento, ecc.


7

ObjectPath è un linguaggio di query semplice e leggero per documenti JSON di struttura complessa o sconosciuta. È simile a XPath o JSONPath, ma molto più potente grazie ai calcoli aritmetici incorporati, ai meccanismi di confronto e alle funzioni integrate.

Esempio

La versione Python è matura e utilizzata in produzione. JS è ancora in beta.

Probabilmente nel prossimo futuro forniremo una versione Javascript a tutti gli effetti. Vogliamo anche svilupparlo ulteriormente, in modo che possa servire come alternativa più semplice alle query Mongo.


1
Solo che non ha quasi documentazione, quindi è difficile capire come fare qualcosa come trovare elementi con testo come qualcosa.
James O'Brien,

1
@ JamesO'Brien Grazie per la tua osservazione - se trovi il riferimento inutile e hai in mente qualche problema specifico, faccelo sapere qui - qualcuno cercherà di aiutarti. Attualmente stiamo lavorando per rendere i documenti più utilizzabili, mi piacerebbe molto i tuoi commenti.
Ela Bednarek,

Grazie, lo apprezzo. Mi piacerebbe usare Attualmente sto usando ashphy.com/JSONPathOnlineEvaluator ?
James O'Brien,

Impossibile capire come usarlo con Javascript a causa della totale mancanza di documentazione.
user3670743,

Siamo alla ricerca di collaboratori che ci possano aiutare. Puoi scrivere su Github o google groups groups.google.com/forum/#!members/objectpath cosa stai cercando di ottenere e sono sicuro che qualcuno risponderà alle tue domande.
Ela Bednarek,

6

Un altro modo di vedere questo sarebbe usare mongoDB. Puoi archiviare il tuo JSON in mongo e quindi interrogarlo tramite la sintassi della query mongodb.


MongoDB è così bello da usare. Vedi la risposta sotto per un esempio di come usare.
serv-inc

4

OK, questo post è un po 'vecchio, ma ... se vuoi fare una query simile a SQL in JSON nativi (o oggetti JS) su oggetti JS, dai un'occhiata a https://github.com/deitch/searchjs

È sia un linguaggio jsql scritto interamente in JSON, sia un'implementazione di riferimento. Puoi dire "Voglio trovare tutti gli oggetti in un array che abbia il nome ===" John "&& age === 25 come:

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

Le ricerche di implementazione di riferimento funzionano nel browser e in un pacchetto npm del nodo

npm install searchjs

Può anche fare cose come join complessi e negazione (NON). Ignora nativamente il caso.

Non fa ancora la somma o il conteggio, ma probabilmente è più facile fare quelli fuori.


3

Ecco alcune semplici librerie javascript che faranno anche il trucco:

  • Dollaro Q è una libreria leggera e piacevole. Ha un'atmosfera familiare alla sintassi concatenata resa popolare da jQuery ed è solo 373 SLOC.
  • SpahQL è un linguaggio di query completo con una sintassi simile a XPath ( Homepage , Github
  • jFunk è un linguaggio di query in corso, con una sintassi simile ai selettori CSS / jQuery. Sembrava promettente, ma non ha avuto alcun sviluppo oltre al suo impegno iniziale.

  • (aggiunto 2014): lo strumento da riga di comando jq ha una sintassi chiara , ma sfortunatamente è una libreria ac. Esempio di utilizzo:

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


3

In MongoDB , è così che funzionerebbe (nella shell mongo, esistono driver per una lingua a tua scelta).

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

I primi tre comandi inseriscono i dati nella tua raccolta. (Basta avviare il mongodserver e connettersi con ilmongo client.)

I prossimi due elaborano i dati. $matchfiltri, $groupapplica la sume list, rispettivamente.


2

SpahQL è il più promettente e ben pensato, per quanto ne so. Consiglio vivamente di provarlo.


2


Ho appena finito una versione rilasciabile di un client JS-lib (defiant.js) che fa quello che stai cercando. Con defiant.js, puoi eseguire una query su una struttura JSON con le espressioni XPath che conosci (nessuna nuova espressione di sintassi come in JSONPath).

Esempio di come funziona (vederlo nel browser qui 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

Come puoi vedere, DefiantJS estende l'oggetto globale JSON con una funzione di ricerca e l'array restituito viene fornito con funzioni di aggregazione. DefiantJS contiene alcune altre funzionalità ma quelle non rientrano nell'ambito di questo argomento. Comunque, puoi testare la libreria con un XPath Evaluator sul lato client. Penso che le persone che non hanno familiarità con XPath troveranno utile questo valutatore.
http://defiantjs.com/#xpath_evaluator

Ulteriori informazioni su defiant.js
http://defiantjs.com/
https://github.com/hbi99/defiant.js

Spero che lo trovi utile ... Saluti


Al momento è possibile ottenere il percorso completo dei risultati?
XeniaSis

2
  1. Google ha un progetto chiamato lovefield ; appena scoperto, e sembra interessante, anche se è più coinvolto che cadere in sottolineatura o lodash.

    https://github.com/google/lovefield

Lovefield è un motore di query relazionale scritto in puro JavaScript. Fornisce inoltre assistenza per la persistenza dei dati sul lato browser, ad esempio utilizzando IndexedDB per archiviare i dati localmente. Fornisce una sintassi simile a SQL e funziona su più browser (attualmente supporta Chrome 37+, Firefox 31+, IE 10+ e Safari 5.1 + ...


  1. Un'altra voce recente interessante in questo spazio chiamato jinqJs .

    http://www.jinqjs.com/

    Rivedendo brevemente gli esempi , sembra promettente e il documento API sembra essere ben scritto.


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 è una libreria javaScript piccola, semplice, leggera ed estensibile che non ha dipendenze. jinqJs fornisce un modo semplice per eseguire query di tipo SQL su array javaScript, raccolte e servizi Web che restituiscono una risposta JSON. jinqJs è simile all'espressione Lambda di Microsoft per .Net e fornisce funzionalità simili per eseguire query su raccolte utilizzando una sintassi simile a SQL e funzionalità di predicato. Lo scopo di jinqJs è quello di fornire un'esperienza simile a SQL ai programmatori che hanno familiarità con le query LINQ.


1

Secondo l'idea di usare semplicemente il tuo javascript, ma per qualcosa di un po 'più sofisticato potresti guardare i dati dojo . Non l'ho mai usato ma sembra che ti dia all'incirca il tipo di interfaccia di query che stai cercando.


1

L'attuale implementazione di Jaql ha come obiettivo l'elaborazione di dati di grandi dimensioni utilizzando un cluster Hadoop, quindi potrebbe essere più del necessario. Tuttavia, funziona facilmente senza un cluster Hadoop (ma richiede comunque che il codice Hadoop e le sue dipendenze vengano compilati, che sono per lo più inclusi). Una piccola implementazione di Jaql che potrebbe essere integrata in Javascript e un browser sarebbe un'ottima aggiunta al progetto.

I tuoi esempi sopra sono facilmente scritti in 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]

Certo, c'è anche molto di più. Per esempio:

// 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 può essere scaricato / discusso su http://code.google.com/p/jaql/


1

Puoi anche usare Underscore.js che è fondamentalmente una libreria di coltelli svizzeri per manipolare le raccolte. utilizzando_.filter , _.pluck, _.reducesi può fare query SQL-like.

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 funziona sia sul lato client che sul lato server ed è una libreria notevole.

Puoi anche usare Lo-Dash che è un fork di Underscore.js con prestazioni migliori.


1

Quando possibile, sposterei tutte le query sul back-end sul server (sul database SQL o su un altro tipo di database nativo). Il motivo è che sarà più veloce e più ottimizzato per eseguire le query.

So che jSON può essere autonomo e potrebbe esserci +/- per avere un linguaggio di query ma non riesco a vedere il vantaggio se stai recuperando i dati dal back-end a un browser, come la maggior parte dei casi d'uso JSON. Esegui query e filtra sul back-end per ottenere dati di dimensioni ridotte necessari.

Se per qualsiasi motivo dovessi eseguire una query sul front-end (principalmente in un browser), ti suggerirei di utilizzare solo array.filter (perché inventare qualcos'altro?).

Detto questo, ciò che penso sarebbe più utile è un'API di trasformazione per JSON ... sono più utili dal momento che una volta che hai i dati potresti voler visualizzarli in diversi modi. Tuttavia, ancora una volta, puoi fare molto di questo sul server (che può essere molto più facile da ridimensionare) che sul client - SE stai usando il server <--> modello client.

Vale solo i miei 2 pence!


1

Dai un'occhiata a https://github.com/niclasko/Cypher.js (nota: sono l'autore)

È un'implementazione Javascript a dipendenza zero del linguaggio di query del database dei grafici Cypher insieme a un database dei grafici. Funziona nel browser (testato con Firefox, Chrome, IE).

Con rilevanza per la domanda. Può essere utilizzato per eseguire query sugli endpoint JSON:

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

Ecco un esempio di query su un documento JSON complesso ed esecuzione di analisi su di esso:

Esempio di query JSON Cypher.js


1

PythonQL offre una sintassi incorporato che IMHO è un miglioramento su SQL, soprattutto perché group, window, where, let, ecc può essere liberamente mescolati.

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

Questo codice mostra due diverse risposte alla tua domanda, a seconda della necessità di gestire l'intera struttura o solo il valore. L'esecuzione ti dà il risultato atteso.

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

0

Puoi usare linq.js.

Ciò consente di utilizzare aggregazioni e selezioni da un set di dati di oggetti, come dati di altre strutture.

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>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.