JSON是否有查询语言?


227

是否有(大致)SQL或类似XQuery的语言来查询JSON?

我正在考虑可以很好地映射到JSON的非常小的数据集,可以轻松地回答诸如“ Y> 3时X的所有值是什么”之类的查询或执行常规的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)

快速Google搜索表明人们已经考虑了这一点并实现了一些东西(JAQL),但是似乎还没有出现标准用法或库集。虽然每个功能单独实现起来都很简单,但是如果有人已经正确地实现了,我不想重新发明轮子。

有什么建议?

编辑:这的确可能是个坏主意,或者JSON可能对于我正在考虑的格式来说太通用了。想要查询语言而不是直接根据需要直接执行sum / etc函数的原因是我希望构建根据用户输入动态查询。Kinda喜欢这样的论点:“我们不需要SQL,我们只需编写所需的函数即可”。最终,这要么变得一发不可收拾,要么随着您的SQL不断深入,最终您编写了自己的SQL版本。(好吧,我知道这是一个愚蠢的争论,但是您明白了。)


我也有这个需要。我需要通过对象树中特定位置的特定值来匹配传入的JSON请求。该查询实际上必须由(高级)用户配置。当前的解决方法是从JSON构建临时XML并应用XPath。
Vladimir Dyuzhev 2011年

1
它更像是一个shell工具,但是jq(stedolan.github.io/jq)对于探索json数据非常有用。在操场上尝试一下:jqplay.org
jtmoulia 2015年

有一个基于Web的工具,可让您在sqall.co上对公共JSON提要或API运行SQL查询。
Stack Man


Answers:


91

当然,如何:

它们似乎都在进行中,但是在某种程度上仍在工作。它们在概念上也类似于XPath和XQuery。即使XML和JSON具有不同的概念模型(层次结构与对象/结构)。

编辑 2015年9月:实际上,现在有了JSON指针标准,该标准允许非常简单和有效地遍历JSON内容。它不仅是正式指定的,而且受许多JSON库支持。因此,我将其称为实际真正有用的标准,尽管由于其有限的表达性,它可能本身也可能不被视为查询语言。


77
换句话说,没有什么标准和稳定的... :-(
Vladimir Dyuzhev 2011年

在谈论标准时,我听说有传言称XQuery 3.1可能会扩展为支持JSON查询(类似于JSONiq)。当然,由于XQuery 3.0尚未正式发布,可能需要一些时间。
朱利安·里邦

哦,怜悯,我绝对希望不会。我见过的所有XML-> JSON尝试都是一团糟-信息模型不兼容。但是我希望看到JQuery使用相同的思想,语法的一部分;正确修改为JSON信息模型。
StaxMan

1
对于正在寻找JSONPath的Ruby实现的任何人:github.com/joshbuddy/jsonpath
Robert Ross

@GôTô:使用MongoDB,如果您有这种自由,似乎是一种可行的方法。(有关如何将查询转换为内置shell的示例,请参见下面答案
serv-inc 2015年

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()之外,是否还有其他查询(例如contains?)
Rikki

5
8年前的最新更新,并且5年前没有被问及该项目是否已终止的回应...我认为该项目已终止。
cfc


14

jmespath的工作原理非常简单而且很好,http: //jmespath.org/ Amazon正在AWS命令行界面中使用它,因此它必须非常稳定。


5
但同时在同一页面上:“如果您需要--query可能无法实现的更多高级功能,则可以签出命令行JSON处理器jq。” 因此,似乎AWS使用jmespath了该--query参数,但建议jq使用命令行管道。docs.aws.amazon.com/cli/latest/userguide/…–
wisbucky

10

JQĴ SON q uery语言,主要用于命令行但绑定到一个广泛的编程语言(Java,Node.js的,PHP,...),甚至在通过浏览器提供的JQ-网络

这是基于原始问题的一些插图,以该JSON为例:

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

Y> 0(等于7)的SUM(X)

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

Y> 0的LIST(X)(等于[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查询库已过时

您可以像想象中一样在委托中放入尽可能多的条件:简单比较,startsWith等。我尚未测试过,但您也可以嵌套过滤器以查询内部集合。


5
array.filter()是JavaScript的一部分,而不是JSON。
伊恩·塞缪尔·麦克莱恩

2
JSON是JavaScript的子集,但是有很多语言支持JSON和数组,并且实现了数组过滤器方法,因此这是很有效的。
dakab


7

ObjectPath是复杂或未知结构的JSON文件简单ligthweigth查询语言。它类似于XPath或JSONPath,但由于嵌入式算术计算,比较机制和内置函数而功能更强大。

例

Python版本已成熟并已在生产中使用。JS仍处于测试阶段。

可能在不久的将来,我们将提供完整的Javascript版本。我们还希望进一步开发它,以便它可以作为Mongo查询的一种更简单的替代方法。


1
除了几乎没有任何文档外,如何查找诸如文本之类的元素的方法很难。
James O'Brien 2014年

1
@ JamesO'Brien感谢您的发言-如果您发现该参考文献无用,并且有任何特定的问题,请在此处告诉我们-有人会尽力提供帮助。我们目前正在努力使文档更加实用,希望您能提出宝贵意见。
Ela Bednarek

谢谢,我很感激。我想用。目前,我正在使用ashphy.com/JSONPathOnlineEvaluator吗?
James O'Brien 2014年

由于完全缺乏文档,因此无法弄清楚如何在Javascript中使用它。
user3670743 '16

我们正在寻找有助于这一点的贡献者。您可以在Github或Google网上论坛groups.google.com/forum/#!members/objectpath上写下您要达到的目标,我敢肯定有人会回答您的问题。
Ela Bednarek '16


4

好的,这篇文章有点老,但是...如果您想在JS对象上的本机JSON(或JS对象)中执行类似SQL的查询,请查看https://github.com/deitch/searchjs

它既是完全用JSON编写的jsql语言,也是参考实现。您可以说:“我想在名称为===“ John” && age === 25的数组中查找所有对象,如下所示:

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

参考实现searchjs可在浏览器以及节点npm包中使用

npm install searchjs

它还可以完成复杂的连接和取反(NOT)之类的事情。它本机忽略大小写。

它尚未进行求和或计数,但在外部进行操作可能会更容易。


3

这是一些简单的javascript库,它们也可以解决这个问题:

  • Dollar Q是一个不错的轻量级库。它对jQuery流行的链接语法具有熟悉的感觉,并且仅为373 SLOC。
  • SpahQL是功能齐全的查询语言,其语法类似于XPath(HomepageGithub
  • jFunk是一种进行中的查询语言,其语法类似于CSS / jQuery选择器。它看起来很有希望,但是除了最初的提交以外没有任何发展。

  • (2014年增加):jq命令行工具具有简洁的语法,但不幸的是它是ac库。用法示例:

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


3

MongoDB中,这就是它的工作方式(在mongo shell中,存在用于您选择的语言的驱动程序)。

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应用sumlist


2

据我所知,SpahQL是其中最有前途且经过深思熟虑的。我强烈建议您检查一下。


2


我刚刚完成了您所需要的客户端JS-lib(defiant.js)的可发布版本。使用defiant.js,您可以使用您熟悉的XPath表达式查询JSON结构(没有像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测试lib。我认为不熟悉XPath的人会发现此评估程序很有用。
http://defiantjs.com/#xpath_evaluator

有关defiant.js的更多信息
http://defiantjs.com/
https://github.com/hbi99/defiant.js

希望您觉得它有用...


当前是否有可能获得结果的完整路径?
XeniaSis '17

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,例如对返回JSON响应的javaScript数组,集合和Web服务执行查询。jinqJs类似于Microsoft的.Net Lambda表达式,它提供类似的功能,可使用类似语法和谓词功能的SQL查询集合。jinqJs的目的是向熟悉LINQ查询的程序员提供类似SQL的体验。


1

我仅支持使用自己的javascript的概念,但是对于更复杂的东西,您可以查看dojo data。尚未使用它,但看起来它大致为您提供了您正在寻找的查询接口。


1

当前的Jaql实现以使用Hadoop集群的大型数据处理为目标,因此可能超出您的需要。但是,它无需Hadoop集群即可轻松运行(但仍需要Hadoop代码及其依赖项进行编译(大多数情况下都包括在内))。可以嵌入Javascript和浏览器中的Jaql的一个小实现将对该项目有很大的帮助。

上面的示例很容易用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 }}]

可以从http://code.google.com/p/jaql/下载/讨论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(为什么要发明其他东西?)。

就是说,我认为对json的转换API会更有用……它们更有用,因为一旦有了数据,您可能想以多种方式显示它。但是,同样,您可以在服务器上做很多事情(扩展起来要容易得多),比在客户端上做得更好-如果您使用的是server <-> client模型。

仅值我的2便士!



1

PythonQL提供了一个嵌入式的语法,恕我直言,是对SQL的改善,主要是因为 groupwindowwherelet,等可以随意混合。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.