Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

JSON Path:

  $.store.book[?@.price < 10].title
Python:

  [x['title'] for x in data['store']['book'] if x['price'] < 10]
Javascript:

  data.store.book.filter(x=>x.price < 10).map(x=>x.title)


All these examples assume an understanding ahead of time of your data structure.

Can you write examples in Python and Javascript where you'd extract those titles from an arbitrary JSON structure? ;-)


I tried this once, and I accidentally invented a poorly implemented and incomplete version of Lisp.


> All these examples assume an understanding ahead of time of your data structure.

How would one use JSONPath to extract all book titles from an arbitrary JSON structure?

Also, when might that use case apply? I can't think of when I've ever needed to do something like this, but I'm interested in learning. :)


JSONPath has excellent documentation, you can absolutely answer that question for yourself very easily.


You mean searching for keys?

  $..book[?@.price<10].title
Yeah, I don't think javascript has that function in the standard library. Writing one is not super complicated, but having to put that into every file (or importing it) is not ideal.

  find_key = (data, key) => {
    if(data instanceof Array){
     return data.map(x=>find_key(x, key)).flat()
    }
    if(data instanceof Object){
     let res = Object.keys(data).map(x=>find_key(data[x], key))
     if(data.hasOwnProperty(key)){
      res.push(data[key])
     }
     return res.flat()
    }
     return []
   }

  find_key(data, "book").filter(x=>x.price < 10).map(x=>x.title)


Yep.

You wouldnt use json path as replacement to any language. It might be marginally useful in configurations or passing queries between different services. But the complex syntax limits it in both cases, because you cannot easily automatically modify the query. In the case of configs it would be great to analyze hundreds of configs on different systems and change them automaticaly, same with queries exchanged between services which might even get stored in a database.

I do not understand why domain languages aren't designed with limited syntax in mind. In the style of lisp for instance. Because actually being able to programatically work with the language is a massive advantage that imo far outweights your own frustration with typing a paranthesis or two extra.


RCL (https://rcl-lang.org):

    [
        for book in input.store.book:
        if book.price < 10:
        book.title
    ]


That javascript version is obviously objectively the best alternative.


I actually prefer the JSONPath version, probably I used to like XPath and I'm not hugely fond of JavaScript.


Yeah, it's not bad. Guido famously preferred the list comprehension style over the functional style, but when you have nested data types and the "monadic style" (ish) functions, it does really make sense. You could imagine it in Python (lets pretend lists have map and filter):

    data['store']['book'].filter(lambda x: x.price < 10).map(lambda x: x.title)
Yeah, not nearly as good. The syntax sugar of a.b instead of a['b'] and arrow functions instead of lambda really does make a pretty big difference.


Best syntax for closures I've ever seen in Scala. Would look something like

    data.store.book.filter(_.price < 10).map(_.title)
Every language should just adapt it.


I’m a fan, but let’s go even further. JavaScript has pleasant definitions of functions with

    filter((x) => x.price < 10)
but why can’t we just write

    filter(x.price < 10)
and add a rule to the JS engine that says “when you encounter a ‘syntax error: undeclared identifier x’, rewrite the code to add `(x) => ` in front of where the syntax error occurred, if and only if this rewrite prevents the syntax error”.

You might protest that reacting to syntax errors by inserting extra code and checking if the errors go away is an insane strategy, but I would note that JavaScript is actually a semicolon-terminated language in which most developers never write a semicolon, and the JavaScript engine is already using this insane strategy on nearly every line of modern JS to insert a semicolon whenever it encounters a syntax error, so it’s obviously practical.


The problem with your approach is that `filter(x.price < 10)` is perfectly valid syntax, it's filter with a single boolean arg. You need something else to trigger the magic: change `x` to `it` and you have Kotlin and Groovy's shorthand syntax -- you just can't define a variable called `it` anymore. If you want closure semantics on arbitrary undefined variables, I think I might have to slap you on general principle ;)


That's exactly what the Raku Programming Language does. Except that the "x" is represented by "*", so it reads:

    grep(*.price < 10)
This is referred to as "Whatever-currying": https://docs.raku.org/type/Whatever*


I dislike that syntax, but it might be better to instead use a special syntax that can't be the name of any variable, like the asterisk in Raku as mentioned below. In such a case, perhaps the function that would call it should check if the value is already the correct type and use that instead of calling it as a function, since then it would be possible for the filter condition to be a constant true or false that does not depend on the values being filtered (this is not usually useful, but it is more consistent and sometimes it is useful).

I think that the automatic semicolon insertion is a bad feature of JavaScript.


Some languages do this already but with a designated placeholder, like

    filter(_.price < 10)
That may not work because plain underscore is already a valid identifier but another placeholder could potentially be used and no need for the parser backtracking / function insertion (which I don't like the idea of, there may be cases where an undeclared identifier was a bug and it shouldn't be turned into a function)


I will never understand why people find the need to cram as much "mystery meat" code into one line as humanly possible. It makes it much harder to understand, debug, and optimize.


The less clutter there is, the more the remaining elements pop.


Cramming a bunch of chained commands on a single line doesn't reduce clutter. In fact, it increases it.


It cuts out the programerese and makes it easier to read?


F# just added this syntax:

  let possibleNow = 
      people 
      |> List.distinctBy _.Name
      |> List.groupBy _.Age
      |> List.map snd
      |> List.map _.Head.Name
      |> List.sortBy _.ToString()


Meanwhile JS is still struggling to define even version 1.0 of a pipe operator, and the proposal has been bikeshedded into shabby oblivion with a syntax that's worse than just pulling out lodash pipe() or similar. TC39 does not fill me with hope.


The Raku programming language has, with some tweaks:

    data.store.book.grep(*.price < 10).map(*.title)
Although personally I would write that as:

    data.store.book.map: { .title if .price < 10 }
which combines the filter / map into a single operation.

https://raku.org


Kotlin has it instead of _

    val numbers = listOf(20, 19, 7, 12)
    val multiplied = numbers.map { 3 * it }
    // [ 60, 57, 21, 36 ]


Raku does a version of that as well, it's sick.


in Raku, this

    data.store.book.filter(_.price < 10).map(_.title)
would be written as

    data.store.book.grep(*.price < 10).map(*.title)


You know, I think you're right. I never realized that Python list comprehension is basically filter/map (and reduce is an external function). That is actually pretty horrible syntax for it from that perspective.


It's also the one that's least optimizable.


If you're that focused on optimization you wouldn't be traversing JSON.

As an aside the js example above could be simplified to a reduce().


With https://www.jsoniq.org, you can do either:

   store.book[][$$.price lt 10].title
or the more verbose:

   for $book in store.book[]
   where $book.price lt 10
   return $book.title


I think in the Javascript version you have to check for null as well.


Those become a bit messier if store or book can be null.


So do you regularly hard code the number 10 in your code?

I think you missed my point.

In realistic code you'd be using string interpolation to put the number 10 into this query language, and worrying about injection vulnerabilities while you did it.

Or even calling another arbitrary function to do the filtering. Which this query language can't handle at all.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: