Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filtering arrays #46

Open
ericwood73 opened this issue Feb 7, 2019 · 8 comments
Open

Filtering arrays #46

ericwood73 opened this issue Feb 7, 2019 · 8 comments

Comments

@ericwood73
Copy link

I'm trying to create a transform that just filters objects from an array, and it works, except the value is a string containing json objects instead of json objects.

A simple example:

I have JSON that looks like this:

{
  "products": [
    {
      "name": "p1",
      "type": "t1"
    },
    {
      "name": "p2",
      "type": "t2"
    },
    {
      "name": "p3",
      "type": "t1"
    }
  ]
}

Applying a transform that selects only those objects from the array with type t1:

{
  "t1_products": {
    "#loop($.products[?(@type=='t1')])": "#currentvalue()"
  }
}

I get this result:
{"t1_products":["{\"name\":\"p1\",\"type\":\"t1\"}","{\"name\":\"p3\",\"type\":\"t1\"}"]}

I was expecting:

{"t1_products":[{"name":"p1","type":"t1"},{"name":"p3","type":"t1"}]}

I have found if I create a new object in the loop like:

{
  "t1_products": {
    "#loop($.products[?(@type=='t1')])": {
      "product": "#currentvalue()"
    }
  }
}

Then I get json objects as the value of each product, but I'd rather not add an unnecessary object to the output.

@Courela
Copy link
Contributor

Courela commented Feb 7, 2019

I don't know if it will work by try using #copy
https://github.com/WorkMaze/JUST.net#bulk-functions

@ericwood73
Copy link
Author

You mean #delete? Passing it a path which resolves to elements that don't meet the criteria using an expression like $.products[?(@type!='t1')]? That would work. However in my case, my path actually selects nodes that have a particular child node, e.g. $.products[?(@type)]. I tried to follow the same idea of selecting those elements that do not have a child. The ! operator is supported in some JsonPath implementation in this way, but apparently not in Json.Net, i.e. this expression results in an error $.products[?(!@type)]. So I couldn't use #delete, because I can't pass it the node paths I want to delete.

@Courela
Copy link
Contributor

Courela commented Feb 7, 2019

I was thinking in #copy, something like this:
{ "t1_products": { "#": [ "#copy($.products[?(@type=='t1')])" ] } }
but it won't work as #copy only accepts jsonPath queries that return a single element.

I've tried changing it to accept multiple results and I've managed to obtain the result you want, but I had to change other stuff that impacts other possible bulk functions that may follow.

I'll get back to this at the weekend.

@Courela
Copy link
Contributor

Courela commented Feb 11, 2019

#48
Well, I've opted by another approach, make "#valueof" capable of handling filters over arrays, It was set to expect only one result from the jsonPath query.
To make it backwads compatible, I've added an optional second parameter, set to true when you want it to return an array or you have a query that returns more than one element. If the query returns no elements, it will return an empty array.

@ericwood73
Copy link
Author

Nice work courela. I actually tried to use #valueof to start and then switched to loop since #valueof didn't support arrays. Are you planning to merge with your develop branch? I'd like to get your custom function changes as well.

@Courela
Copy link
Contributor

Courela commented Feb 12, 2019

I am waiting for @WorkMaze to eventually merge the pull requests, then combine them all. I don't want to create a parallel package, since I'm only a contributor, all the work was done by him.

@Courela
Copy link
Contributor

Courela commented Apr 11, 2019

Since #48 was rolled back by #50, #57 will return the expected result that you typed in first comment, an array of objects instead of an array of strings.

@Courela
Copy link
Contributor

Courela commented Aug 23, 2019

Funny, I didn't realize that this was possible until now:
{ "t1_products": { "#loop($.products[?(@type=='t1')])": "#currentvalue()" } }
I thought that you always had to build an object as value of a #loop property. With #57 you should get the result that you expected in first place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants