Using jsonpath to get parent node - jsonpath

Using node JSONPath, how can I get the parent node name from child node value
{
"store": {
"book": [
{
"id":"1",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"id":"2",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
}
]
}
}
I use this expression to identify the child node based on value, I want to use this child node to find the parent node
$.[?(#.id =="1")]

You do not specify which implementation of JSON Path, but with both Gatling (Scala) and JayWay (Java) you can use nested filters to filter by children while returning the parent, grandparent or whatever. Here is a sample:
With this JSON:
{
"a": {
"b": {
"c": {
"d": {
"e": "foo"
}
},
"something": "bar"
}
}
}
And this path:
$.a.b[?(#.c[?(#.d[?(#.e == "foo")])])].something
Returns:
[ "bar" ]
I am able to retrieve b by using expressions to get to lower nodes as the filter.
Some other implementations error out on these expressions.

Unfortunately, JSONpath does not support search by parameters in the contents of a child object:
http://goessner.net/articles/JsonPath/

With JayWay it works but the query provided by Jayson is wrong, because if you change the value to "foo2" it will still return "bar".
This can be tested on http://jsonpath.herokuapp.com/.
Query:
$.a.b[?(#.c.d.e=="foo")].something
Returns:
["bar"]
Query:
$.a.b[?(#.c.d.e=="foo2")].something
Returns:
[]

Related

Using jq to get arrays where a key within the array is equal to a specific value?

I have been practicing with jq play to try to get all the arrays in a list where website is == "google" and create another json list from that.
https://jqplay.org/s/DKNC2mhOLq
jq: error (at :18): Cannot index array with string "website"
exit status 5
{
"items": [
{
"name":"name1",
"id":"1",
"website":"google"
},
{
"name":"name1",
"id":"1",
"website":"google"
},
{
"name":"name1",
"id":"2",
"website":"jingle"
}
]
Desired output:
[
{
"name":"name1",
"id":"1",
"website":"google"
},
{
"name":"name1",
"id":"1",
"website":"google"
}
]
how can I loop through arrays in a list and look for specific values for specific keys? Thanks for any help or ideas you can provide. I am a begginer with JSON and jq.
Enclose the select with a map, as you want to apply the filter to each array item individually while retaining the surrounding array structure.
jq '.items | map(select(.website == "google"))'
[
{
"name": "name1",
"id": "1",
"website": "google"
},
{
"name": "name1",
"id": "1",
"website": "google"
}
]
Demo

Storing optional attributes in DynamoDB's putItem via step functions

I have defined a state machine in AWS step functions and one of my states is storing an item to DynamoDB
...
"Store item": {
"End": true,
"Type": "Task",
"Resource": "arn:aws:states:::dynamodb:putItem",
"Parameters": {
"Item": {
"foo": {
"S.$": "$.data.foo"
},
"bar": {
"S.$": "$.data.bar"
},
"baz": {
"S.$": "$.data.baz"
},
},
"TableName": "nrp_items"
}
},
...
The problem starts from the fact that baz property is optional, ie not exist in some cases.
On those cases, the putItem task fails:
An error occurred while executing the state 'Store item' (entered at the event id #71). > The JSONPath '$.data.baz' specified for the field 'S.$' could not be found in the input
My backup plan is to use a lambda to perform that type of operation, but can I do it directly using the putItem task in steps function?
I was wondering if:
Is possible to somehow inject via JSONPath my whole $.data item to the "Item" property, something like:
...
"Store item": {
"End": true,
"Type": "Task",
"Resource": "arn:aws:states:::dynamodb:putItem",
"Parameters": {
"Item": "$.data",
"TableName": "nrp_items"
}
},
...
OR
2) Define that the baz property is optional
TL;DR We can deal with optional variables with a "Variable": "$.baz", "IsPresent": true Choice condition to handle no-baz cases.
The Amazon States Language spec does not have optional properties: Step Functions will throw an error if $.baz does not exist in the input. We can avoid undefined paths by inserting a two-branch Choice State, one branch of which handles baz-exists cases, the other no-baz cases. Each branch continues with a Pass State that reworks the data input into dynamo-format Item syntax, using Parameters. The put-item task's "Item.$": "$.data" (as in your #1) contains only foo-bar when baz is not defined, but all three otherwise.
{
"StartAt": "HasBazChoice",
"States": {
"HasBazChoice": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.baz",
"IsPresent": true,
"Next": "MakeHasBazItem"
}
],
"Default": "MakeNoBazItem"
},
"MakeHasBazItem": {
"Type": "Pass",
"Parameters": {
"data": {
"foo": { "S.$": "$.foo"},
"bar": { "S.$": "$.bar"},
"baz": { "S.$": "$.baz"}
}
},
"Next": "PutItemTask"
},
"MakeNoBazItem": {
"Type": "Pass",
"Parameters": {
"data": {
"foo": {"S.$": "$.foo"},
"bar": {"S.$": "$.bar"}
}
},
"Next": "PutItemTask"
},
"PutItemTask": {
...
"Parameters": {
"TableName": "my-table",
"Item.$": "$.data"
}
},
}
}
If you have more than one optional field, your lambda backup plan is the better option - the above workaround would become unwieldy.

Access definitions on ref property with newtonsoft.json.schema

I want to have access to the definitions in the schema in order to get the naming of the definition. I am using newtonsoft.json v11.01
I am building a c# converter for jsonschema to make a syntaxtree and compile it in order to get a typed version of the object at runtime.
{
"$id": "https://example.com/arrays.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "xml remarks",
"type": "object",
"properties": {
"fruits": {
"type": "array",
"items": {
"type": "object",
"title": "fruit",
"required": ["naam"],
"properties": {
"naam": {
"type": "string",
"description": "The name of the fruit."
}
}
}
},
"vegetables": {
"type": "array",
"items": { "$ref": "#/definitions/veggie" }
}
},
"definitions": {
"veggie": {
"type": "object",
"required": [ "veggieName", "veggieLike" ],
"properties": {
"veggieName": {
"type": "string",
"description": "The name of the vegetable."
},
"veggieLike": {
"type": "boolean",
"description": "Do I like this vegetable?"
}
}
}
}
}
in the schema a reference is created with the name veggie. This is used in the property vegetable with a reference.
Json schema contains a definition on the root object but is doesn't have it on the property element. On the property element there is nothing identifiable to point to the right definition.
how do i find the right definition for the property?
In general, in order to resolve a json-pointer (a $ref is a "uri-reference", and the part after the # is a "json-pointer"), you need to have access to the root of the json document.
So if you currently have a function that only gets an argument that points to the "properties" section, then you need to give that function a second argument that points to the root of the document.
(It gets more complicated when you're using a schema made up of more than one file; then you need a second argument that points to the roots of all the schema documents)
It's one of the more difficult parts of writing software that interprets json-schema files, especially if your language/library doesn't have support for json-pointers built-in - you'll need to write it yourself in that case.

How to form inner SubQuery in Gremlin Server (Titan 1.0)?

I'm using Following Query :
g.V(741440).outE('Notification').order().by('PostedDateLong', decr).range(0,1).as('notificationInfo').match(
__.as('notificationInfo').inV().as('postInfo'),
).select('notificationInfo','postInfo')
it is giving following result :
{
"requestId": "9846447c-4217-4103-ac2e-de3536a3c62a",
"status": {
"message": "",
"code": ​200,
"attributes": { }
},
"result": {
"data": [
{
"notificationInfo": {
"id": "c0zs-fw3k-347p-g2g0",
"label": "Notification",
"type": "edge",
"inVLabel": "Comment",
"outVLabel": "User",
"inV": ​749664,
"outV": ​741440,
"properties": {
"ParentPostId": "823488",
"PostedDate": "2016-05-26T02:35:52.3889982Z",
"PostedDateLong": ​635998269523889982,
"Type": "CommentedOnPostNotification",
"NotificationInitiatedByVertexId": "1540312"
}
},
"postInfo": {
"id": ​749664,
"label": "Comment",
"type": "vertex",
"properties": {
"PostImage": [
{
"id": "amto-g2g0-2wat",
"value": ""
}
],
"PostedByUser": [
{
"id": "am18-g2g0-2txh",
"value": "orbitpage#gmail.com"
}
],
"PostedTime": [
{
"id": "amfg-g2g0-2upx",
"value": "2016-05-26T02:35:39.1489483Z"
}
],
"PostMessage": [
{
"id": "aln0-g2g0-2t51",
"value": "hi"
}
]
}
}
}
],
"meta": { }
}
}
I want to get information of Vertex "NotificationInitiatedByVertexId" (Edge Property ) in the response as well.
For that i tried following query :
g.V(741440).outE('Notification').order().by('PostedDateLong', decr).range(0,2).as('notificationInfo').match(
__.as('notificationInfo').inV().as('postInfo'),
g.V(1540312).next().as('notificationByUser')
).select('notificationInfo','postInfo','notificationByUser')
Note : I tried directly with vertex Id in subquery as I wasn't aware how to dynamically get value from edge property in query itself.
It is giving error. I tried a lot but am not able to find any solution.
I'm assuming that you are storing a Titan generated identifier in that edge property called NotificationInitiatedByVertexId. If so, please consider the following even though this first part doesn't really answer your question. I don't think you should store a vertex identifier on the edge. Your graph model should explicitly track the relationship of NotificationInitiatedBy with an edge and by storing the identifier of the vertex on the edge itself you are bypassing that. Also, if you ever have to migrate your data in some way, the ids won't be preserved (Titan will generate new ones) and trying to sort that out will be a mess.
Even if that is not a Titan generated identifier and a logical one you created, I still think I would look to adjust your graph schema and promote that Notification to a vertex. Then your Gremlin traversals would flow more easily.
Now, assuming you don't change that, then I don't see a reason to not just issue two queries in the same request and then combine the results to one data structure. You just need to do a lookup with the vertex id which is going to be pretty fast and inexpensive:
edgeStuff = g.V(741440).outE('Notification').
order().by('PostedDateLong', decr).range(0,1).as('notificationInfo').
... // whatever logic you have
select('notificationInfo','postInfo').next()
vertexStuff = g.V(edgeStuff.get('notificationInfo').value('NotificationInitiatedByVertexId')).next()
[notificationInitiatedBy: vertexStuff, notification: edgeStuff]

Refs to # in a definition don't parse inJson.net schema

I have a schema that has a 'manager' property which is a user object:
{
"id": "foo.com/schemas/user",
"manager": {
"anyOf": [{
"$ref": "#/definitions/user"
}],
"title": "Manager"
}
The #/definitions/user schema is:
"definitions": {
"user": {
"$ref": "#"
}
}
This results in a "Error when resolving schema reference '#'. Path 'definitions.user'" error.
Addressing the user with "$ref": "#" from the manager property isn't an option as we are using the definition to help build the UI and need a common definition.
Edit: added the "id" property which was a critical omission in this.
This works:
{
"id": "http://foo.com/schemas/user",
"properties":{
"manager":{
"anyOf":[
{
"$ref":"#/definitions/user"
}
],
"title":"Manager"
}
},
"definitions":{
"user":{
"$ref":"#"
}
}
}
https://github.com/JamesNK/Newtonsoft.Json.Schema/issues/33
Edit: Added fixed "id" field with http:// qualification added.

Resources