jsonPath predicate to return the whole JSON - jsonpath

I would like to return the whole JSON if a condition is matched.
Test Json:
{
"EVENTID": 2624367601,
"RECEIVERNAME": "CM.MYHR",
"SENDERNAME": "CM.EIS.CF1",
"AGREEMENTNAME": null
}
I keep trying in https://jsonpath.curiousconcept.com, but couldn't figure it out.
I thought the following expression should work, but it always return empty.
$.[?(#.SENDERNAME==CM.EIS.CF1)]
Please help.

You only have a fragment of a json. Try it like this:
{
"events": [
{
"EVENTID": 2624367601,
"RECEIVERNAME": "CM.MYHR",
"SENDERNAME": "CM.EIS.CF1",
"AGREEMENTNAME": null
}
]
}
And use:
$.*[?(#.SENDERNAME=='CM.EIS.CF1')]

If you want while json as it is from input, then as per my understanding you have to use below expression:
$.
I have tested it in https://jsonpath.curiousconcept.com/

Related

How do I select a specific property in nested array json rails 5

I need help with this. I would like to access transactionCustomFields and I would like to get the token from the response.
{
"event":"TRANSACTION OUTCOME",
"timestamp":1672749136029,
"data":{
"transactionId":"b5247b19-1e14-4f3e-818f-a3b1554dd64b",
"transactionStatus":"SUCCESS",
"statusDescription":"SUCCESS",
"transaction":{
"id":"b5247b19-1e14-4f3e-818f-a3b1554dd64b",
"paymentMethod":"MOBILE_MONEY",
"transactionType":"PULL",
"phoneNumber":"+256754187853",
"telecom":"AIRTEL",
"amount":500,
"status":"SUCCESS",
"narration":"",
"failedDescription":null,
"webhookUrl":"https://webhook.site/cbf423c2-15f5-46f3-9c76-1dcc0b9a2e18",
"createdAt":"2023-01-03T12:32:04.176Z",
"transactionCustomFields":[
{
"id":"1fc25a5c-ba0b-4959-b295-31628d8da0e1",
"key":"token",
"value":"31644"
},
{
"id":"2686effb-4f40-45ac-867f-b39d84282dae",
"key":"reference",
"value":"1672749122"
}
]
}}}
This is the JSON response
Assuming you want to access the first item of the "transactionCustomFields" array and its id/key you could do something like this.
json_object = JSON.parse(response)
json_object['data']['transaction']["transactionCustomFields"][0]["key"] //gives you token
json_object['data']['transaction']["transactionCustomFields"][0]["id"] //gives you "1fc25a5c-ba0b-4959-b295-31628d8da0e1"
Hope this answers your question

filtering Dynamo DB in Step functions JSONPath

I am trying to build a step function that has a choice state based on a map in a result of a dynamo db map. An example result from my dynamo GetItem request would be.
{
"Item": {
"organisationId": {
"S": "Andys-test"
},
"id": {
"S": "Andy2"
},
"states": {
"L": [
{
"M": {
"year": {
"N": "2021"
},
"status": {
"S": "started"
}
}
},
{
"M": {
"year": {
"N": "2022"
},
"status": {
"S": "started"
}
}
}
]
},
},
My condition will be checking the status of the states map against the year 2021. I have attempted to use this JSONPath which from what I can tell is valid, although I am getting nothing in the data flow simulator in the step functions console. I have tried various iterations of the below, with quotes escaped quotes etc and can't get anything to parse the correct value out.
I have been doing this in the input selector as I can see that the result path does not support the [?()] notation.
$.Item.states.L..M[?(#.year.N == 2022) ]
Without an example choice state with some rules, it'll be hard to answer definitively but I think I'm following.
JSONPath with expression filters
I run into this sort of problem more often than I'd like when using JSONPath filter expressions and have to add "helper" tasks to get things moving (wasting valuable state transitions 😣 ).
When you specify a Path that includes a filter expression, the result is always going to be a list (and you won't be able to reference index afterwards either).
ChoiceRules don't really have a comparator that deals with arrays/lists (at least i haven't been able to get it to work, so let me know if you do 😄).
The hack I've found easiest to reason about/maintain is creating a simple Pass Task that "pops" the values I need from the filter expression and then pass that along to the Choice Task.
Here's an example from one of my previous answers (the pattern used in the PassDef task would be defined before your choice task in your scenario, instead of after)
I've found it easier to start with https://jsonpath.herokuapp.com then progress to the data flow simulator. Just remember to always keep in mind whether
you're trying implement a Path or a Reference Path!

Apply filter to an entity within an object using JSONPath

I have the following JSON:
{
"value": {
"activate": false
}
}
I want the JSONPath value to returned as true, but on applying the filter as below:
$.value.?(#.activate==false)
I get an invalid result.
Is there anything wrong with the JSONPath?
The syntax for filter queries needs brackets.
$.value[?(#.activate==false)]

AWS AppSync Query to shape response data (Similar to Group By in SQL)

I have one DynamoDB table with all the data I need for the client, however, I want to shape the data the client receives to reduce client-side manipulation.
My Schema:
type StateCounty {
id: ID!
StateName: String
CountyName: String
FIPSST: Int
FIPSCNTY: Int
Penetration: String
Date: String
}
and to return a custom query I have the type:
type Query {
getStateCountybyState(StateName: String): StateCountyConnection
}
This works - and with a simple query
query getStateCountybyState {
getStateCountybyState (StateName: "Delaware") {
items {
StateName
CountyName
Date
}
}
}
the results are returned as expected:
{
"StateName": "Delaware",
"CountyName": "Kent",
"Date": "02-01-2017"
},
{
"StateName": "Delaware",
"CountyName": "Sussex",
"Date": "02-01-2016"
},
{
"StateName": "Delaware",
"CountyName": "New Castle",
"Date": "02-01-2018"
}
etc.
I would like to return the data in the following format:
{
"StateName": "Delaware" {
{ "CountyName": "Kent",
"Date": "02-01-2017"
},
{
"CountyName": "Sussex",
"Date": "02-01-2016"
},
{
"CountyName": "New Castle",
"Date": "02-01-2018"
}
}
}
I have tried adding GroupCounty: [StateCountyGroup] to the schema:
type StateCounty {
id: ID!
StateName: String
CountyName: String
FIPSST: Int
FIPSCNTY: Int
Penetration: String
Date: String
GroupCounty: [StateCountyGroup]
}
and then a reference to that in the query
query getStateCountybyState {
getStateCountybyState (StateName: "Delaware") {
items {
StateName
CountyName
Date
GroupCounty: [StateCountyGroup]
}
}
}
I think my issue is within the resolver - currently, it is configured to use the StateName as a key, but I am not sure how to pass the StateName from the primary query to the subquery.
Resolver:
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
"expression" : "StateName = :StateName",
"expressionValues" : {
":StateName" : { "S" : "${context.arguments.StateName}" },
}
},
"index" : "StateName-index-copy",
"select" : "ALL_ATTRIBUTES",
}
Any guidance appreciated - I have gone through the documentation several times, but cannot find an example.
UPDATE
I tried the suggestion below from Richard - and it is definitely on the right track, however, despite multiple variations on the theme, I either return null or the following error (I eliminated some of the county objects returned in the error for brevity):
"message": "Unable to convert set($myresponse = {\n \"Delaware\":
[{SSA=8000, Eligibles=32295, FIPS=10001, StateName=Delaware, SSACNTY=0,
Date=02-01-2016, CountyName=Kent, Enrolled=3066, Penetration=0.0949,
FIPSCNTY=1, FIPSST=10, SSAST=8, id=6865},
{SSA=8010, Eligibles=91332, FIPS=10003, StateName=Delaware, SSACNTY=10, Date=02-01-2016, CountyName=New Castle, Enrolled=10322, Penetration=0.113, FIPSCNTY=3, FIPSST=10, SSAST=8, id=6866},
{SSA=0, Eligibles=10, FIPS=10, StateName=Delaware, SSACNTY=0, Date=02-01-2018, CountyName=Pending County Designation, Enrolled=0, Penetration=0, FIPSCNTY=0, FIPSST=10, SSAST=0, id=325},
{SSA=8000, Eligibles=33371, FIPS=10001, StateName=Delaware, SSACNTY=0, Date=02-01-2017, CountyName=Kent, Enrolled=3603, Penetration=0.108, FIPSCNTY=1, FIPSST=10, SSAST=8, id=3598},
{SSA=8020, Eligibles=58897, FIPS=10005, StateName=Delaware, SSACNTY=20, Date=02-01-2016, CountyName=Sussex, Enrolled=3760, Penetration=0.0638, FIPSCNTY=5, FIPSST=10, SSAST=8, id=6867}) \nnull\n\n to class java.lang.Object."
}
]
}
From reading the above, it sounds like your original query is returning the correct results that you want but not in the response format that you would prefer, as you would like the "StateName" to be a top-level JSON key with the value being a JSON object of the state which you passed in as an argument. Is that accurate? If so then why not use the same query that already works but with a different response template. Something like:
#set($myresponse = {
"$ctx.args.StateName": $ctx.result.items
})
$util.toJson($myresponse)
Note that $myresponse isn't exactly the same as you had above as your example with "stateName" : "Delaware" { ... } wasn't completely valid JSON so I didn't want to make an assumption on what a good structure would be, but the point remains if you're already getting the proper results from your query I would just try to change the structure of your GraphQL results.
Now if I misread the above and you're NOT getting the proper results from the query, the other way that I could read your statement of "primary query to the subquery" is that you're trying to apply an additional "filter" to your query results. If that is the case then you need something like this:
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
"expression" : "StateName = :StateName",
"expressionValues" : {
":StateName" : { "S" : "${context.arguments.StateName}" },
}
},
"index" : "StateName-index-copy",
"select" : "ALL_ATTRIBUTES",
"filter" : {
"expression" : "#population >= :population",
"expressionNames" : {
"#population" : "population"
},
"expressionValues" : {
":population" : $util.dynamodb.toDynamoDBJson($ctx.args.population)
}
}
}
I used an example here where maybe your query also needed to filter by the population size in each county. This may not be representative of what you're looking for but hopefully it helps.
EDITED WITH MORE INFORMATION 4/16/18
I've written up more information on this in a step-by-step manner, to go through the concepts in pieces.
The key here is not just the response template, but also the fields that you're requesting to be returned (as this is the nature of GraphQL). Let's walk through this by way of example. Now that you're returning an individual item with GraphQL (since your response template is converting an array to a single item) so you'll need to change the expected GraphQL query response type. Suppose you have a GraphQL type in your schema like this:
type State {
id: ID!
population: String!
governor: String!
}
type Query {
allStates: [State]
}
If you just convert the response in the template as above you'll see an error like "type mismatch error, expected type LIST" if you run something like this:
query {
allStates{
id
population
}
}
That's because your response is no longer returning the individual items. Instead you'll need to change the GraphQL response type [State] to match what your template conversion is doing State like so:
type State {
StateName: String
}
type Query {
allStates: State
}
Now if your resolver request template is doing something that returns a list of items (like a DynamoDB scan or Query) you can convert the list to a single item in the response template like so:
#set($convert = {"StateName" : $ctx.result.items })
$util.toJson($convert)
Then run the following GraphQL query:
query {
allStates{
StateName
}
}
And you'll get a single object containing an array of your results back:
{
"data": {
"allStates": {
"StateName": "[{id=1, population=10000, governor=John Smith}]"
}
}
}
However while this might be pointing out the errors you are having, this is returning a StateName and from your original question I think you are looking to do a bit more by combining records in the response for some optimization, along with some potential filtering. One way to do this would be to create an array (or you could create a map {}) and populate it based on some conditional. For example modify your query to have a StateName as an argument:
type Query {
allStates(StateName: String!): Post
}
Then you can filter on this in the resolver response template, by using a #foreach and an #if() conditional, then calling .add() only if items in the response are for the state which you requested:
#set($convert = {"StateName" : [] })
#foreach($item in $ctx.result.items)
#if($item["StateName"]=="$ctx.args.StateName")
$util.qr($convert.get("StateName").add("$item"))
#end
#end
$util.toJson($convert)
So now you could run something like this:
query {
allStates(StateName:"Texas"){
StateName
}
}
And this will give you back just the results for that specific state which you passed as an argument. But you'll notice the selection set of the query is StateName. You could introduce a bit more flexibility by having the possible states listed in your GraphQL type:
type State {
StateName: String
Seattle: String
Texas: String
}
Now you alter your resolver response template to use the argument for building up the return array since it can specify this in the selection set:
#set($convert = {"$ctx.args.StateName" : [] })
#foreach($item in $ctx.result.items)
#if($item["StateName"]=="$ctx.args.StateName")
$util.qr($convert.get("$ctx.args.StateName").add("$item"))
#end
#end
$util.toJson($convert)
So I can run this query:
query {
allPosts(StateName:"Seattle"){
Seattle
}
}
And I get back my result. Note though that passing Seattle as the argument but requesting back Texas:
query {
allPosts(StateName:"Seattle"){
Texas
}
}
This will not work as the response object you created in your map was Seattle: [...] but you had Texas as the selection set.
The final thing that you might want to do is have multiple states returned, which you could do by building up one giant map keyed by the state name, or maybe it's done using the arguments or the selection set through adding state names to the return type as demonstrated above. That's up to you so I'm not sure how you'll want that but hopefully this demonstrates how you can manipulate the responses to meet your needs.

filter the Json according to string in an array in JSONPATH

I have a situation where I have json String that has a child as Array that contains only Strings. Is there as way I can get the object reference of the arrays that contains a specific String.
Example:
{ "Books":{
"History":[
{
"badge":"y",
"Tags":[
"Indian","Culture"
],
"ISBN":"xxxxxxx",
"id":1,
"name":"Cultures in India"
},
{
"badge":"y",
"Tags":[
"Pre-historic","Creatures"
],
"ISBN":"xxxxxxx",
"id":1,
"name":"Pre-historic Ages"
}
]
}
}
To Achieve:
From the above JSON String, need to get all books in History which contains "Indian" inside the "tags" list.
I am using JSONPATH in my project but If there is other API that can provide similar functionality, any help is welcome.
If you're using Goessner JSONPath, $.Books.History[?(#.Tags.indexOf('Indian') != -1)] as mentioned by Duncan above should work.
If you're using the Jayway Java port (github.com/jayway/JsonPath), then
$.Books.History[?(#.Tags[?(# == 'Indian')] != [])] or more elegantly, use the in operator like this $.Books.History[?('Indian' in #.Tags)]. Tried them both here.
Assuming you are using Goessner JSONPath (http://goessner.net/articles/JsonPath/) the following should work:
$.Books.History[?(#.Tags.indexOf('Indian') != -1)]
According to the Goessner site, you can use underlying JavaScript inside the ?() filter. You can therefore use the JavaScript indexOf function to check if your Tags array contains the tag 'Indian'.
See a working example here using this JSONPath query tester:
http://www.jsonquerytool.com/sample/jsonpathfilterbyarraycontents
Did you try to use underscoreJS ? You can get the Indian books like this :
var data = {"Books:"....};
var indianBooks = _.filter(data.Books.History, function(book) { return _.contains(book.Tags, "Indian"); })

Resources