Use JSONPath to extract nodes from different levels - jsonpath

Given this document:
{
"k1": "v1",
"k2": "v2",
"k3": "v3",
"k4": {
"k4.1": "v4.1",
"k4.2": "v4.2",
"k4.3": "v4.3"
}
}
I need to extract this subset, in this exact form:
{
"k2": "v2",
"k3": "v3",
"k4.1": "v4.1"
"k4.2": "v4.2"
}
But despite searching/experimenting for over a day, I am unable to discern the proper incantation.
This expression: $['k2', 'k3'] gives me the two top level elements:
{
"k2" : "v2",
"k3" : "v3"
}
And this expression: $['k4']['k4.1','k4.2'] gives me the two nested elements:
{
"k4.1" : "v4.1",
"k4.2" : "v4.2"
}
But how to combine these two expressions into one that includes the results from multiple levels?
Unfortunately the nature of the tool I am using (AWS State Language paths) demands that this be done with a single xpath expression.

I think the reason it is not working is the Path only specifies a single path, you can't append multiple paths in a single expression.
You could use Parameters to define a custom/static schema for your input to a task. The flow is as follows State-Input->InputPath->Parameters.
Using the input you supplied, and a Lambda Function which just echoes the input back, the following worked for me:
{
"StartAt": "HelloWorld",
"States": {
"HelloWorld": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:XXXXXXXXX:function:LambdaFunctionToEchoInput",
"Parameters": {
"k2.$": "$.k2",
"k3.$": "$.k3",
"k4.1.$": "$.k4.['k4.1']",
"k4.2.$": "$.k4.['k4.2']"
},
"End": true
}
}
}

Related

Convert the JSON attribute from smallcase to uppercase in XQuery and Marklogic 10

I have loaded the below JSON in MarkLogic and I need to convert the Name property value to upper case:
{ "Name": "User", "Id": "1", "date": "2022-01-01" }
Any way to convert the value to upper case in Marklogic and XQuery, looking like below format?
{ "Name": "USER", "Id": "1", "date": "2022-01-01" }
One way would be to select the Name, use upper-case() and create a text() node, and then use xdmp:node-replace().
Assuming that you have the document assigned to a variable $doc:
let $name := $doc/Name
return xdmp:node-replace($name, text {upper-case($name) } )
For reference, there are a few examples in the documentation of updating different types of properties:
https://docs.marklogic.com/guide/app-dev/json#id_60123

Extracting values with jq only when they exist

I have a large file of records that contain fields that look something like this:
{
"id": "1000001",
"updatedDate": "2018-12-21T01:52:00Z",
"createdDate": "1993-11-30T02:59:25Z",
"varFields": [
{
"fieldTag": "b",
"content": "1000679727"
},
{
"fieldTag": "v",
"content": "v.1"
}
}
I need to extract the .content element along with other things, but only when the fieldTag associated with it is "v". Only some records contain a fieldTag "v".
When I try to parse using
(.varFields[] |select(.fieldTag=="v") | "\(.content)") // ""
it works fine so long as v is present. However, when it is not present, I get
jq: error (at <stdin>:353953): Cannot iterate over null (null)
I tried to get rid of the error with multiple variations, including things to the effect of
(select((.varFields[] |select(.fieldTag=="v") | .content) != null) | .varFields[] |select(.fieldTag=="v") | "\(.content)") // ""
but I'm still getting the same error. What am I missing?
Take a look at the error suppression operator ? that works a bit like the new ?. nullable chaining operator in Javascript.
The ? operator, used as EXP?, is shorthand for try EXP.
Example:
jq '[.[]|(.a)?]'
Input [{}, true, {"a":1}]
Output [null, 1]
They have a slightly simpler demonstrable example of this at https://jqplay.org/jq?q=%5B.%5B%5D%7C(.a)%3F%5D&j=%5B%7B%7D%2C%20true%2C%20%7B%22a%22%3A1%7D%5D and the try-catch operator is similar if all you need is custom error handling (or just error ignoring...).

Extract values from web service JSON response with JSONPath

I have a JSON response from web service that looks something like this :
[
{
"id":4,
"sourceID":null,
"subject":"SomeSubjectOne",
"category":"SomeCategoryTwo",
"impact":null,
"status":"completed"
},
{
"id":12,
"sourceID":null,
"subject":"SomeSubjectTwo",
"category":"SomeCategoryTwo",
"impact":null,
"status":"assigned"
}
]
What I need to do is extract the subjects from all of the entities by using JSONPATH query.
How can I get these results :
Subject from the first item - SomeSubjectOne
Filter on specific subject value from all entities (SomeSubjectTwo for example)
Get Subjects from all entities
Goessner's orinial JSONPath article is a good reference point and all implementations more or less stick to the suggested query syntax. However, implementations like Jayway JsonPath/Java, JSONPath-Plus/JavaScript, flow-jsonpath/PHP may behave a little differently in some areas. That's why it can be important to know what implementation you are actually using.
Subject from the first item
Just use an index to select the desired array element.
$.[0].subject
Returns:
SomeSubjectOne
Specific subject value
First, go for any elements .., check those with a subject [?(#.subject] and use == '..' for comparison.
$..[?(#.subject == 'SomeSubjectTwo')]
Returns
[ {
"id" : 12,
"sourceID" : null,
"subject" : "SomeSubjectTwo",
"category" : "SomeCategoryTwo",
"impact" : null,
"status" : "assigned" } ]*
Get all subjects
$.[*].subject
or simply
$..subject
Returns
[ "SomeSubjectOne", "SomeSubjectTwo" ]

Finding JSONPath value by a partial key

I have the following JSON:
{
"Dialog_1": {
"en": {
"label_1595938607000": "Label1",
"newLabel": "Label2"
}
}
}
I want to extract "Label1" by using JSONPath. The problem is that each time I get a JSON with a different number after "label_", and I'm looking for a consistent JSONPath expression that will return the value for any key that begins with "label_" (without knowing in advance the number after the underscore).
It is not possible with JSONPath. EL or Expression Language does not have sch capability.
Besides, I think you need to review your design. Why the variable name is going to be changed all the time? If it is changing then it is data and you need to keep it in a variable. You cannot keep data in data.

Meteor query based on the value of elements in an array inside an object

I am new to meteor and mongoDB and have been searching for an answer to this question for some time without any luck.
I have multiple documents in MongoDB similar to the one below:
{
"_id" : ObjectId("5abac4ea0c31d26804421371"),
"Points" : [
{
"Value" : 6.869752766626993,
"Time" : 1522284528946
},
{
"Value" : 3.9014587731230477,
"Time" : 1522284543946
},
{
"Value" : 1.2336926618519772,
"Time" : 1522284558946
},
{
"Value" : 6.504837583667155,
"Time" : 1522284573946
},
{
"Value" : 9.824138227740864,
"Time" : 1522284588946
},
{
"Value" : 9.707480757899235,
"Time" : 1522284603946
},
{
"Value" : 4.6122167850338105,
"Time" : 1522284618946
}
]
}
How can I implement a query in meteor that returns an array containing all the Points from all documents with 'Time' field greater than certain value?
As Jankapunkt has pointed out in his comment, it might be a lot easier and better if you created a new collection Points where each document includes only Value and Time attributes. The given example would then become seven separate documents rather than a single array.
It does nevertheless happen, that we want to query documents according to some inner values, e.g. attributes in objects in arrays.
Taken from the mongodb documentation on querying embedded documents, we can just use dot notation for this.
If you do not know the index position of the document nested in the array, concatenate the name of the array field, with a dot (.) and the name of the field in the nested document.
Such as for your question (assuming Points to be the name of your collection):
db.points.find( { 'Points.Time': { $gte: 123412341234 } } )
Which looks almost identical in Meteor:
Points.find({ 'Points.Time': { $gte: 123412341234 } })

Resources