How do I KQL to verify presence of property in child object? - kql

I have query which returns object below. How do I return results only if policies array below contains element with policyDefinitionId equal to somevalue without using contains keyword
{
"isComplianceCheck": "False",
"resourceLocation": "southcentralus",
"ancestors": "thc-platform-mg,8f5a5a7f-3cdb-48f1-a894-351a54b84920",
"policies": "[{\"policyDefinitionId\":\"/providers/Microsoft.Authorization/policyDefinitions/34f95f76-5386-4de7-b824-0d8478470c9d/\",\"policySetDefinitionId\":\"/providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8/\",\"policyDefinitionReferenceId\":\"diagnosticsLogsInLogicAppsMonitoring\",\"policySetDefinitionName\":\"1f3afdf9-d0c9-4c3d-847f-89da613e70a8\",\"policyDefinitionName\":\"34f95f76-5386-4de7-b824-0d8478470c9d\",\"policyDefinitionEffect\":\"AuditIfNotExists\",\"policyAssignmentId\":\"/providers/Microsoft.Management/managementGroups/8f5a5a7f-3cdb-48f1-a894-351a54b84920/providers/Microsoft.Authorization/policyAssignments/a45ca010a72c41ceac351431/\",\"policyAssignmentName\":\"a45ca010a72c41ceac351431\",\"policyAssignmentScope\":\"/providers/Microsoft.Management/managementGroups/8f5a5a7f-3cdb-48f1-a894-351a54b84920\",\"policyExemptionIds\":[]}]",
"eventCategory": "Policy",
"entity": "/subscriptions/3adcdebe-b99e-4781-bcdb-65a58a976594/resourceGroups/thc-man-scus-monitoring-rg/providers/Microsoft.Logic/workflows/this-man-scus-reboot-logic",
"message": "Microsoft.Authorization/policies/audit/action",
"hierarchy": "",
"caller": "me#me.com",
"eventDataId": "474c5466-033a-4910-90a1-0ce47d80f1c5",
"eventSubmissionTimestamp": "2021-11-24T15:22:22.7433954Z",
"httpRequest": "{\"clientIpAddress\":\"47.188.89.222\"}",
"resource": "this-man-scus-reboot-logic",
"resourceGroup": "THC-MAN-SCUS-MONITORING-RG",
"resourceProviderValue": "MICROSOFT.LOGIC",
"subscriptionId": "3adcdebe-b99e-4781-bcdb-65a58a976594",
"activityStatusValue": "Success"
}

Here you go:
let MyTable = datatable(d:dynamic) [
dynamic({
"prop1": "value1",
"prop2": "value2",
"policies": "[{\"policyKey1\":\"policyValue1\",\"policyKey2\":\"policyValue2\",\"policyKey3\":\"policyValue3\"},{\"policyKey10\":\"policyValue10\",\"policyKey20\":\"policyValue20\",\"policyKey30\":\"policyValue30\"}]"
}),
dynamic({
"prop1": "value10",
"prop2": "value20",
"policies": "[{\"policyKeyA\":\"policyValueA\",\"policyKeyB\":\"policyValueB\",\"policyKeyC\":\"policyValueC\"},{\"policyKeyAA\":\"policyValueAA\",\"policyKeyBB\":\"policyValueBB\",\"policyKeyCC\":\"policyValueCC\"}]"
}),
dynamic({
"prop1": "value100",
"prop2": "value200",
"policies": "[{\"policyKeyA\":\"policyValueAA\",\"policyKeyB\":\"policyValueB\",\"policyKeyC\":\"policyValueC\"},{\"policyKeyAA\":\"policyValueAA\",\"policyKeyBB\":\"policyValueBB\",\"policyKeyCC\":\"policyValueCC\"}]"
}),
];
MyTable
| mv-apply policy = todynamic(tostring(d.policies)) on
(
mv-expand policy
| where policy['policyKeyA'] == 'policyValueA'
)
| project-away policy
Result:
d
{ "prop1": "value10", "prop2": "value20", "policies": "[{"policyKeyA":"policyValueA","policyKeyB":"policyValueB","policyKeyC":"policyValueC"},{"policyKeyAA":"policyValueAA","policyKeyBB":"policyValueBB","policyKeyCC":"policyValueCC"}]"}
Explanation:
you'll need to use two tricks to solve this one:
You need to use mv-apply in order to iterate over all the items in the policy object, and then filter for the exact policy you're looking for (for example, | where policy['policyKeyA'] == 'policyValueA').
Because the value of policies isn't really a json, but rather a string that represents a json, and because when extracting from a dynamic object you get a dynamic object as well - you can't just iterate over d.policies - you'll need to first convert this from dynamic to string, and then create a dynamic from this string, like this: todynamic(tostring(d.policies))

Related

Transform JSON: select one row from array of json objects

I can't get a specific row from this JSON array.
So I want to get the object where filed 'type' is equal to 'No-Data'
Are there exist any functions in SQL to take the row or some expressions?
"metadata": { "value": "JABC" },
"force": false
"users": [
{ "id": "111", "comment": "aaa", type: "Data" },
{ "id": "222", "comment": "bbb" , type:"No-Data"},
{ "id": "333", "comment": "ccc", type:"Data" }
]
You can use a JSON path query:
select jsonb_path_query_first(the_column, '$.users[*] ? (#.type == "No-Data")')
from the_table
This assumes that the column is defined as jsonb (which it should be). If it's not you have to cast it: the_column::jsonb
Online example

Get JSON Array from JSON Object and Count Number of Objects

I have a column that contains some data like this:
{
"activity_goal": 200,
"members": [
{
"json": "data"
},
{
"HAHA": "HAHA"
},
{
"HAHA": "HAHA"
}
],
"name": "Hunters Team v3",
"total_activity": "0",
"revenue_goal": 200,
"total_active_days": "0",
"total_raised": 300
}
I am using cast(team_data -> 'members' as jsonb) to get the "Members" JSON array, which gives me a column like this:
[
{
"json": "data"
},
{
"HAHA": "HAHA"
},
{
"HAHA": "HAHA"
}
]
I am using array_length(cast(team_data -> 'members' as jsonb), 1) to pull a column with the number of Members that exist in the list. When I do this, I am given this error:
function array_length(jsonb, integer) does not exist
Note: I have also tried casting as "json" instead of "jsonb"
I am following this documentation. What am I doing wrong?
Use the JSON functions when working with json such as json_array_length
select json_array_length(team_data -> 'members') from mytable

Query to extract ids from a deeply nested json array object in Presto

I'm using Presto and trying to extract all 'id' from 'source'='dd' from a nested json structure as following.
{
"results": [
{
"docs": [
{
"id": "apple1",
"source": "dd"
},
{
"id": "apple2",
"source": "aa"
},
{
"id": "apple3",
"source": "dd"
}
],
"group": 99806
}
]
}
expected to extract the ids [apple1, apple3] into a column in Presto
I am wondering what is the right way to achieve this in Presto Query?
If your data has a regular structure as in the example you posted, you can use a combination of parsing the value as JSON, casting it to a structured SQL type (array/map/row) and the using array processing functions to filter, transform and extract the elements you want:
WITH data(value) AS (VALUES '{
"results": [
{
"docs": [
{
"id": "apple1",
"source": "dd"
},
{
"id": "apple2",
"source": "aa"
},
{
"id": "apple3",
"source": "dd"
}
],
"group": 99806
}
]
}'),
parsed(value) AS (
SELECT cast(json_parse(value) AS row(results array(row(docs array(row(id varchar, source varchar)), "group" bigint))))
FROM data
)
SELECT
transform( -- extract the id from the resulting docs
filter( -- filter docs with source = 'dd'
flatten( -- flatten all docs arrays into a single doc array
transform(value.results, r -> r.docs) -- extract the docs arrays from the result array
),
doc -> doc.source = 'dd'),
doc -> doc.id)
FROM parsed
The query above produces:
_col0
------------------
[apple1, apple3]
(1 row)

RavenDb facet search in string array field with wildcard

Is it possible to have a RavenDb faceted search, in a string[] field, where I would want to show facets (counts) for only values starting with a particular string, rather a range?
I'll try to explain myself better to with a simple example, imagine having an index with the below entries
ID | Values
-------------------------
1 | CatPersian, CatNormal, DogLabrador
2 | CatPersian, Camel, DogPoodle
3 | CatNormal, CatBengali, DogNormal
4 | DogNormal
I would perform a query on the above documents, and the Facet search would include a range of 'Cat*', on the 'Values' field. Is this possible? Then, I would get a result based on just the different values for cats, like:
CatPersian [2]
CatNormal [2]
CatBengali [1]
Yes, you can do that. Index the array, and then just use facets normally.
Let's see the full example. You have the following documents:
{
"Name": "John",
"FavoriteAnimals": [
"Cats",
"Dogs",
"Snails"
],
"#metadata": {
"#collection": "Kids"
}
}
{
"Name": "Jane",
"FavoriteAnimals": [
"Cats",
"Rabits"
],
"#metadata": {
"#collection": "Kids"
}
}
Now, you create the following index:
from k in docs.Kids
from animal in k.FavoriteAnimals
select new { Animal = animal }
And run this query:
from index 'YourIndex'
where startsWith(Animal , 'ca')
select facet('Animal')
And the result will be:
{
"Name": "Animal",
"Values": [
{
"Count": 2,
"Range": "cats"
}
]
}
Alternatively, you can use this index:
from k in docs.Kids
select new { k.FavoriteAnimals }
And run this query:
from index 'YourIndex'
where startsWith(FavoriteAnimals , 'ca')
select facet('FavoriteAnimals')
The difference here is that you'll get all matches for the documents that have a match.
So in this case
{
"Name": "Animal",
"Values": [
{
"Count": 2,
"Range": "cats"
},
{
"Count": 1,
"Range": "dogs"// also, snails, rabbits
}
]
}

RestKit Mapping concatenate

I have some json like this :
{
"items": [
{
"datas": [
{
"date": "2015-01-20T00:00+0100"
},
{
"date": "2015-01-21T00:00+0100"
}
],
"id": "100"
},
{
"datas": [
{
"date": "2015-01-20T00:00+0100"
},
{
"date": "2015-01-21T00:00+0100"
}
],
"id": "200"
}
],
"id": "itemset1"
}
I have an Object, data, with some info and a date.
I would like to set a property identifier to a value composed with the parent id and the date, like 100_2015-01-20T00:00+0100
I can get the parent id in my identifier with the following code :
[dataMapping addAttributeMappingsFromDictionary:#{"#parent.id":#"identifier",...}];
Is they a way do concatenate value with RestKit mapping?
You can't concatenate directly, no. Instead you would store both of the attributes and provide a public method which concatenates and returns the value. Or perhaps set the variables to transient and on willSave (or similar) convert them and persistently store the concatenated value.