JsonPath: getting first element in string list - json

On https://jsonpath.com I have below example, using expression
$.phoneNumbers[?(#.id < 3)].number
on below JSON object.
{
"firstName": "John",
"lastName" : "doe",
"age" : 26,
"phoneNumbers": [
{
"type" : "iPhone",
"number": "0123-4567-1111",
"id": 1
},
{
"type" : "home",
"number": "0123-4567-2222",
"id": 2
},
{
"type" : "home",
"number": "0123-4567-3333",
"id": 3
}
]
}
Result is
[
"0123-4567-1111",
"0123-4567-2222"
]
Question
I only want the first string "0123-4567-1111", but appending [0] to my expression does not work. Expression $.phoneNumbers[?(#.id < 3)].number[0] gives result ["0","0"]. How can I get the first returned string?

Indeed you were very close to it by using this expression -
$.phoneNumbers[?(#.id < 3)].number[0]
In this expression you used id but in the json there is no id key so it resulted in undefined
try the expression like this using index -
$.phoneNumbers[0].number
It will return number from the first object of phoneNumbers list as : ["0123-4567-8888"]
If you want to go by conditional basis use the below expression which will return the number of type iphone -
$.phoneNumbers[?(#.type == 'iPhone')].number
Output -
["0123-4567-8888"]

Related

How to flatten this json in datafactory

I have a API json response. The response has the same blocks type of data nested and i need to flatten this via the Azure datafactory. The depth of the children is variable. I'm not a expert in ADF and i couldn't find a example of how to fix this. I suspect that i need some recursive function to do this.
Some guidance would be very much appreciated.
Example json:
[
{
"id" : 1,
"name" : "item 1",
"children" : []
},
{
"id" : 2,
"name" : "item 2",
"children" : [
{
"id" : 3,
"name" : "item 3",
"children" : [
{
"id" : 4,
"name" : "item 4",
"children" : []
}
]
}
]
}
]
And i need to transform it into a sql table:
id
name
1
item 1
2
item 2
3
item 3
4
item 4
You will have to use Mapping data flow in Azure Data factory and use multiple Flatten transformations to get the desired output.

Filter json properties by name using JSONPath

I'd like to select all elements with a certain match in the name of the property.
For example, all the properties whose name starts with 'pass' from this json:
{
"firstName": "John",
"lastName" : "doe",
"age" : 50,
"password" : "1234",
"phoneNumbers": [
{
"type" : "iPhone",
"number": "0123-4567-8888",
"password": "abcd"
},
{
"type" : "home",
"number": "0123-4567-8910",
"password": "fghi"
}
]
}
Would result something like this:
[
"1234",
"abcd",
"fghi"
]
I don't want filter by values, only by property names. Is it possible using jsonpath?
I'm using the method SelectTokens(string path) of Newtonsoft.Json.Linq
No, JSONPath defines expressions to traverse through a JSON document to reach to a subset of the JSON. It cannot be used when you don't know the exact property names.
In your case you need property values whose name starts with a specific keyword. For that, you need to traverse the whole JSON text and look for the property names which start with pass having a string type
var passwordList = new List<string>();
using (var reader = new JsonTextReader(new StringReader(jsonText)))
{
while (reader.Read())
{
if(reader.TokenType.ToString().Equals("PropertyName")
&& reader.ValueType.ToString().Equals("System.String")
&& reader.Value.ToString().StartsWith("pass"))
{
reader.Read();
passwordList.Add(reader.Value.ToString());
}
}
passwordList.ForEach(i => Console.Write("{0}\n", i));
}

Mongolite group by/aggregate on JSON object

I have a json document like this on my mongodb collection:
Updated document:
{
"_id" : ObjectId("59da4aef8c5d757027a5a614"),
"input" : "hi",
"output" : "Hi. How can I help you?",
"intent" : "[{\"intent\":\"greeting\",\"confidence\":0.8154089450836182}]",
"entities" : "[]",
"context" : "{\"conversation_id\":\"48181e58-dd51-405a-bb00-c875c01afa0a\",\"system\":{\"dialog_stack\":[{\"dialog_node\":\"root\"}],\"dialog_turn_counter\":1,\"dialog_request_counter\":1,\"_node_output_map\":{\"node_5_1505291032665\":[0]},\"branch_exited\":true,\"branch_exited_reason\":\"completed\"}}",
"user_id" : "50001",
"time_in" : ISODate("2017-10-08T15:57:32.000Z"),
"time_out" : ISODate("2017-10-08T15:57:35.000Z"),
"reaction" : "1"
}
I need to perform group by on intent.intent field and I'm using Rstudio with mongolite library.
What I have tried is :
pp = '[{"$unwind": "$intent"},{"$group":{"_id":"$intent.intent", "count": {"$sum":1} }}]'
stats <- chat$aggregate(
pipeline=pp,
options = '{"allowDiskUse":true}'
)
print(stats)
But it's not working, output for above code is
_id count
1 NA 727
If intent attribute type is string and keep the object as string.
We can split it to array with \" and use third item of array.
db.getCollection('test1').aggregate([
{ "$project": { intent_text : { $arrayElemAt : [ { $split: ["$intent", "\""] } ,3 ] } } },
{ "$group": {"_id": "$intent_text" , "count": {"$sum":1} }}
])
Result:
{
"_id" : "greeting",
"count" : 1.0
}

Need a json path expression for below json

Need a JSON path expression for below JSON. I wanted to extract "Id" for each specific "name"
For Example: I need to extract "Id" : "3" for "name" : "XYZ" .
I tried a JSON path expression as $..Id which given output as:
[
"1",
"2",
"3"
]
But I needed an Id specific to "name": "XYZ"`
[
{
"primary":{
"name":"ABC"
},
"Id":"1"
},
{
"primary":{
"name":"PQR"
},
"Id":"2"
},
{
"primary":{
"name":"XYZ"
},
"Id":"3"
}
]
Able to resolve this by below expression
$..[?(#.primary.name == 'XYZ')].Id

Search within array object

I have a the following json object --
{
"Title": "Terminator,
"Purchases": [
{"Country": "US", "Site": "iTunes"},
{"Country": "FR", "Site": "Google"}
]
}
Given the above object, here is how the search results show yield:
"Titles on iTunes in US" ==> YES, show "Terminator"
"Titles on Google in FR" ==> YES, show "Terminator"
"Titles on iTunes in FR" ==> NO
However, if I just AND the query, to get Titles with Purchase.Country="FR" and Titles with Purchase.Site="iTunes", it would erroneously show the above result, since both conditions are met. However, I want to restrict that facet to within the purchase item. The equivalent in python code would be:
for purchase in item['Purchases']:
if purchase['Country'] == "FR" and purchase['Site'] == "iTunes":
return True
Currently it works like this:
for purchase in item['Purchases']:
if purchase['Country'] == "FR":
has_fr = True
if purchase['Site'] == "iTunes":
has_itunes = True
if has_itunes and has_fr: return True
How would this be done in ElasticSearch?
First, you need to index the "Purchases" field as a nested field, by defining the mapping of your object type like this:
{
"properties" : {
"Purchases" : {
"type" : "nested",
"properties": {
"Country" : {"type": "string" },
"Site" : {"type": "string" }
}
}
}
}
Only then will ElasticSearch keep the association between the individual countries and the individual sites, as described here.
Next, you should use a nested query, such as this one:
{ "query":
{ "nested" : {
"path" : "Purchases",
"score_mode" : "avg",
"query" : {
"bool" : {
"must" : [
{
"match" : {"Purchases.Country" : "US"}
},
{
"match" : {"Purchases.Site" : "iTunes"}
}
]
}
}
}
}
}
This will return your object if the query combines "US" and "iTunes", but not if it combines "US" and "Google". The details are described here.