Existe-t-il un langage de requête pour JSON?


227

Existe-t-il un langage (à peu près) similaire à SQL ou XQuery pour interroger JSON?

Je pense à de très petits ensembles de données qui correspondent bien à JSON où il serait bien de répondre facilement à des requêtes telles que "quelles sont toutes les valeurs de X où Y> 3" ou de faire les opérations de type SUM / COUNT habituelles.

Comme exemple complètement inventé, quelque chose comme ceci:

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

Je pense que cela fonctionnerait à la fois côté client et côté serveur avec des résultats convertis en la structure de données spécifique à la langue appropriée (ou peut-être conservée en JSON)

Une brève recherche sur Google suggère que les gens y ont pensé et ont implémenté quelques éléments ( JAQL ), mais il ne semble pas qu'un usage standard ou un ensemble de bibliothèques ait encore émergé. Bien que chaque fonction soit assez simple à mettre en œuvre seule, si quelqu'un l'a déjà bien fait, je ne veux pas réinventer la roue.

Aucune suggestion?

Edit: Cela peut en effet être une mauvaise idée ou JSON peut être un format trop générique pour ce que je pense .. La raison de vouloir un langage de requête au lieu de simplement faire les fonctions de sommation / etc. les requêtes basées dynamiquement sur les entrées utilisateur. Un peu comme l'argument selon lequel "nous n'avons pas besoin de SQL, nous pouvons simplement écrire les fonctions dont nous avons besoin". Finalement, cela devient incontrôlable ou vous finissez par écrire votre propre version de SQL à mesure que vous la poussez de plus en plus. (D'accord, je sais que c'est un peu un argument stupide, mais vous avez l'idée ..)


J'ai aussi un tel besoin. J'ai besoin de faire correspondre les demandes JSON entrantes par des valeurs spécifiques à des emplacements spécifiques dans l'arborescence d'objets. La requête doit en fait être configurée par un utilisateur (expérimenté). La solution de contournement actuelle consiste à créer un XML de fortune à partir de JSON et à appliquer XPath.
Vladimir Dyuzhev

1
C'est plus un outil shell, mais jq ( stedolan.github.io/jq ) a été génial pour explorer les données json. Essayez-le dans la cour de récréation: jqplay.org
jtmoulia

Il existe un outil Web qui vous permet d'exécuter des requêtes SQL sur des flux JSON publics ou des API sur sqall.co .
Stack Man


Réponses:


91

Bien sûr, que diriez-vous:

Ils semblent tous être un peu de travail en cours, mais fonctionnent dans une certaine mesure. Ils sont également similaires à XPath et XQuery conceptuellement; même si XML et JSON ont des modèles conceptuels différents (hiérarchique vs objet / struct).

EDIT Sep-2015: En fait, il existe maintenant la norme JSON Pointer qui permet une traversée très simple et efficace du contenu JSON. Il est non seulement spécifié formellement, mais également pris en charge par de nombreuses bibliothèques JSON. Je dirais donc que c'est un véritable standard utile, bien qu'en raison de son expressivité limitée, il puisse ou non être considéré comme un langage de requête en soi.


77
en d'autres termes, rien de standard et stable ... :-(
Vladimir Dyuzhev

En parlant de standard, j'ai entendu une rumeur selon laquelle XQuery 3.1 pourrait être étendu pour prendre en charge les requêtes JSON (similaire à JSONiq ). Bien sûr, cela pourrait prendre un certain temps car XQuery 3.0 n'est pas encore officiellement sorti.
Julien Ribon

Oh miséricorde, j'espère vraiment que non. Toutes les tentatives XML-> JSON que j'ai vues ont été horribles. Les modèles d'information sont incompatibles. Mais je voudrais voir JQuery utiliser les mêmes idées, des parties de la syntaxe; juste correctement modifié en modèle info JSON.
StaxMan

1
Pour tous ceux qui recherchent une implémentation Ruby de JSONPath: github.com/joshbuddy/jsonpath
Robert Ross

@ GôTô: Utiliser MongoDB, si vous avez cette liberté, semble être une approche viable. (voir la réponse ci-dessous pour un exemple de traduction de la requête dans le shell intégré)
serv-inc

48

Je recommanderais mon projet sur lequel je travaille, appelé jLinq . Je suis à la recherche de commentaires, donc je serais intéressé à entendre ce que vous pensez.

Si vous permet d'écrire des requêtes similaires à ce que vous feriez dans 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)
        };
    });

Il est également entièrement extensible!

La documentation est toujours en cours, mais vous pouvez toujours l'essayer en ligne.


@hugoware: existe-t-il une documentation à ce sujet. Y a-t-il des requêtes autres que .starts () (comme contient?)
Rikki

5
Dernière mise à jour il y a 8 ans et aucune réponse à la question de savoir si le projet est mort il y a 5 ans ... Je pense que le projet est mort.
cfc


14

jmespath fonctionne vraiment très facilement et bien, http://jmespath.org/ Il est utilisé par Amazon dans l'interface de ligne de commande AWS, donc il doit être assez stable.


5
Pourtant, en même temps sur la même page: "Si vous avez besoin de fonctionnalités plus avancées qui ne sont pas possibles avec --query, vous pouvez consulter jq, un processeur JSON en ligne de commande." Il semble donc qu'AWS utilise jmespathpour le --queryparamètre, mais recommande jqpour la tuyauterie de ligne de commande. docs.aws.amazon.com/cli/latest/userguide/…
wisbucky

10

jq est un J SON q langue uery, principalement destinés à la ligne de commande , mais avec des liaisons à un large éventail de langages de programmation (Java, Node.js, php, ...) et même disponible dans le navigateur via JQ-web .

Voici quelques illustrations basées sur la question d'origine, qui a donné ce JSON comme exemple:

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

SUM (X) O Y Y> 0 (équivaudrait à 7)

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

LISTE (X) O Y Y> 0 (équivaudrait à [3,4])

map(.y > 0)

la syntaxe jq étend la syntaxe JSON

Chaque expression JSON est une expression jq valide, et des expressions telles que [1, (1+1)]et {"a": (1 + 1)} `illustrent comment jq étend la syntaxe JSON.

Un exemple plus utile est l'expression jq:

{a,b}

qui, étant donné la valeur JSON {"a":1, "b":2, "c": 3}, évalue {"a":1, "b":2}.


8

La array.filter()méthode intégrée rend la plupart de ces bibliothèques de requêtes javascript obsolètes

Vous pouvez mettre autant de conditions à l'intérieur du délégué que vous pouvez l'imaginer: comparaison simple, démarre avec, etc. Je n'ai pas testé mais vous pourriez probablement imbriquer des filtres aussi pour interroger les collections internes.


5
array.filter()fait partie de JavaScript, pas JSON.
Iain Samuel McLean Elder

2
JSON est un sous-ensemble de JavaScript, mais il existe de nombreux langages qui prennent en charge JSON et les tableaux et qui ont une méthode de filtre de tableau implémentée, c'est donc un point valide.
dakab

7

Si vous utilisez .NET, Json.NET prend en charge les requêtes LINQ par-dessus JSON. Ce message contient quelques exemples. Il prend en charge le filtrage, le mappage, le regroupement, etc.


7

ObjectPath est un langage de requête simple et léger pour les documents JSON de structure complexe ou inconnue. Il est similaire à XPath ou JSONPath, mais beaucoup plus puissant grâce aux calculs arithmétiques intégrés, aux mécanismes de comparaison et aux fonctions intégrées.

Exemple

La version Python est mature et utilisée en production. JS est toujours en version bêta.

Dans un proche avenir, nous fournirons probablement une version Javascript à part entière. Nous voulons également le développer davantage, afin qu'il puisse servir d'alternative plus simple aux requêtes Mongo.


1
Sauf qu'il n'a pratiquement pas de documentation, il est donc difficile de savoir comment faire quoi que ce soit comme trouver des éléments avec du texte comme quelque chose.
James O'Brien

1
@ JamesO'Brien Merci pour votre remarque - si vous trouvez la référence inutile et avez un problème spécifique en tête, faites-le nous savoir ici - quelqu'un essaiera de vous aider. Nous travaillons actuellement à rendre les documents plus utilisables, j'adorerais vos commentaires.
Ela Bednarek

Merci - je l'apprécie. Je voudrais utiliser. Actuellement, j'utilise ashphy.com/JSONPathOnlineEvaluator ?
James O'Brien

Impossible de comprendre comment utiliser cela avec Javascript en raison d'un manque total de documentation.
user3670743

Nous recherchons des contributeurs pour vous aider. Vous pouvez écrire sur Github ou sur google groups groups.google.com/forum/#!members/objectpath ce que vous essayez de réaliser, et je suis sûr que quelqu'un répondra à vos questions.
Ela Bednarek


4

OK, ce post est un peu vieux, mais ... si vous voulez faire une requête de type SQL dans des objets JSON natifs (ou JS) sur des objets JS, jetez un œil à https://github.com/deitch/searchjs

Il s'agit à la fois d'un langage jsql écrit entièrement en JSON et d'une implémentation de référence. Vous pouvez dire: "Je veux trouver tous les objets d'un tableau dont le nom est ===" John "&& age === 25 comme:

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

L'implémentation de référence searchjs fonctionne dans le navigateur ainsi que dans un package npm de nœud

npm install searchjs

Il peut également faire des choses comme les jointures complexes et la négation (NON). Il ignore nativement la casse.

Il ne fait pas encore de sommation ni de comptage, mais il est probablement plus facile de les faire à l'extérieur.


3

Voici quelques bibliothèques javascript simples qui feront également l'affaire:

  • Dollar Q est une jolie bibliothèque légère. Il a une sensation familière à la syntaxe de chaînage rendue populaire par jQuery et n'est que de 373 SLOC.
  • SpahQL est un langage de requête complet avec une syntaxe similaire à XPath ( Homepage , Github
  • jFunk est un langage de requête en cours, avec une syntaxe similaire aux sélecteurs CSS / jQuery. Il semblait prometteur, mais n'a pas eu de développement au-delà de son engagement initial.

  • (ajouté en 2014): l' outil de ligne de commande jq a une syntaxe soignée, mais malheureusement c'est une bibliothèque ac. Exemple d'utilisation:

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


3

Dans MongoDB , c'est ainsi que cela fonctionnerait (dans le shell mongo, il existe des pilotes pour une langue de votre choix).

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

Les trois premières commandes insèrent les données dans votre collection. (Il suffit de démarrer le mongodserveur et de se connecter avec lemongo client.)

Les deux suivants traitent les données. $matchfiltres, $groupapplique respectivement le sumet list.


2

Le SpahQL est le plus prometteur et le mieux pensé de ceux-ci, pour autant que je sache. Je recommande fortement de le vérifier.


2


Je viens de terminer une version libérable d'un JS-lib côté client (defiant.js) qui fait ce que vous cherchez. Avec defiant.js, vous pouvez interroger une structure JSON avec les expressions XPath que vous connaissez (pas de nouvelles expressions de syntaxe comme dans JSONPath).

Exemple de fonctionnement (voir dans le navigateur ici 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

Comme vous pouvez le voir, DefiantJS étend l'objet global JSON avec une fonction de recherche et le tableau renvoyé est livré avec des fonctions d'agrégation. DefiantJS contient quelques autres fonctionnalités mais celles-ci sont hors de portée pour ce sujet. Quoi qu'il en soit, vous pouvez tester la bibliothèque avec un évaluateur XPath côté client. Je pense que les personnes qui ne connaissent pas XPath trouveront cet évaluateur utile.
http://defiantjs.com/#xpath_evaluator

Plus d'informations sur defiant.js
http://defiantjs.com/
https://github.com/hbi99/defiant.js

J'espère que vous le trouverez utile ... Cordialement


Est-il actuellement possible d'obtenir le chemin complet vers les résultats?
XeniaSis

2
  1. Google a un projet appelé lovefield ; vient de le découvrir, et cela semble intéressant, bien qu'il soit plus complexe que de simplement passer en soulignement ou lodash.

    https://github.com/google/lovefield

Lovefield est un moteur de recherche relationnel écrit en JavaScript pur. Il fournit également de l'aide sur la persistance des données côté navigateur, par exemple en utilisant IndexedDB pour stocker des données localement. Il fournit une syntaxe de type SQL et fonctionne sur plusieurs navigateurs (prend actuellement en charge Chrome 37+, Firefox 31+, IE 10+ et Safari 5.1 + ...


  1. Une autre entrée récente intéressante dans cet espace appelée jinqJs .

    http://www.jinqjs.com/

    En examinant brièvement les exemples , cela semble prometteur et le document API semble bien rédigé.


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 est une petite bibliothèque javaScript simple, légère et extensible qui n'a pas de dépendances. jinqJs fournit un moyen simple d'effectuer des requêtes de type SQL sur des tableaux javaScript, des collections et des services Web qui renvoient une réponse JSON. jinqJs est similaire à l'expression Lambda de Microsoft pour .Net, et il fournit des capacités similaires pour interroger des collections en utilisant une syntaxe SQL et une fonctionnalité de prédicat. Le but de jinqJs est de fournir une expérience de type SQL aux programmeurs familiarisés avec les requêtes LINQ.


1

J'appuierai l'idée d'utiliser simplement votre propre javascript, mais pour quelque chose d'un peu plus sophistiqué, vous pourriez regarder les données du dojo . Je ne l'ai pas utilisé, mais il semble que cela vous donne à peu près le type d'interface de requête que vous recherchez.


1

L'implémentation Jaql actuelle cible un traitement de données volumineux à l'aide d'un cluster Hadoop, il se peut donc que ce soit plus que ce dont vous avez besoin. Cependant, il s'exécute facilement sans cluster Hadoop (mais nécessite toujours le code Hadoop et ses dépendances pour être compilés, qui sont généralement inclus). Une petite implémentation de Jaql qui pourrait être intégrée dans Javascript et le navigateur serait un excellent ajout au projet.

Vos exemples ci-dessus sont facilement écrits en 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]

Bien sûr, il y en a beaucoup plus. Par exemple:

// 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 peut être téléchargé / discuté sur http://code.google.com/p/jaql/


1

Vous pouvez également utiliser Underscore.js, qui est essentiellement une bibliothèque swiss-knife pour manipuler les collections. En utilisant _.filter, _.pluck, _.reducevous pouvez le faire SQL comme les requêtes.

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 fonctionne à la fois côté client et côté serveur et est une bibliothèque remarquable.

Vous pouvez également utiliser Lo-Dash qui est un fork de Underscore.js avec de meilleures performances.


1

Dans la mesure du possible, je déplacerais toutes les requêtes vers le backend sur le serveur (vers la base de données SQL ou un autre type de base de données native). La raison en est qu'il sera plus rapide et plus optimisé pour effectuer les requêtes.

Je sais que jSON peut être autonome et il peut y avoir +/- pour avoir un langage de requête, mais je ne vois pas l'avantage si vous récupérez des données du backend vers un navigateur, comme la plupart des cas d'utilisation JSON. Recherchez et filtrez au niveau du backend pour obtenir les données aussi petites que nécessaire.

Si, pour une raison quelconque, vous devez interroger le front-end (principalement dans un navigateur), je vous suggère d'utiliser simplement array.filter (pourquoi inventer autre chose?).

Cela dit, ce que je pense serait plus utile, c'est une API de transformation pour json ... elles sont plus utiles car une fois que vous avez les données, vous pouvez les afficher de plusieurs façons. Cependant, encore une fois, vous pouvez faire une grande partie de cela sur le serveur (qui peut être beaucoup plus facile à mettre à l'échelle) que sur le client - SI vous utilisez le modèle client <--> serveur.

Juste ma valeur de 2 pence!


1

Consultez https://github.com/niclasko/Cypher.js (remarque: je suis l'auteur)

Il s'agit d'une implémentation Javascript sans dépendance du langage de requête de base de données graphique Cypher avec une base de données graphique. Il s'exécute dans le navigateur (testé avec Firefox, Chrome, IE).

En rapport avec la question. Il peut être utilisé pour interroger les points de terminaison JSON:

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

Voici un exemple d'interrogation d'un document JSON complexe et d'analyse sur celui-ci:

Exemple de requête JSON Cypher.js


1

PythonQL offre une syntaxe intégrée qui à mon humble avis est une amélioration sur SQL, principalement parce que group, window, where, let, etc. peuvent être librement entremêlés.

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

Ce code montre deux réponses différentes à votre question, selon votre besoin de gérer la structure entière ou juste la valeur. L'exécution vous donne le résultat attendu.

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

0

Vous pourriez utiliser linq.js.

Cela permet d'utiliser des agrégations et des sélections à partir d'un ensemble de données d'objets, comme d'autres données de structures.

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>

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.