JsonPath: get root element depending on first level sub-element - jsonpath

I need all elements (including "id" and all attributes) of the json sample below where "type" has the value "state_machine_state", but only if "type" is on the first level. I don't want the middle element "order_transaction" in the result, although it has "type": "state_machine_state" in the second hierarchy level.
[
{
"id": "f45aa035eb424d26a0529d25b3647c32",
"type": "state_machine_state",
"attributes": {
"technicalName": "cancelled",
"name": "Cancelled",
"stateMachineId": "7553ad2630044fa589d786135d5000ad",
"customFields": null,
"createdAt": "2020-06-05T14:23:30.503+02:00",
"updatedAt": null,
"translated": {
"name": "Cancelled",
"customFields": []
},
"apiAlias": null
}
},
{
"id": "2d24ed4179824dbe92eee2f3d4f885b1",
"type": "order_transaction",
"relationships": {
"stateMachineState": {
"data": {
"type": "state_machine_state",
"id": "21f236e8955f45d3931fc9e44615088a"
}
}
},
"meta": null
},
{
"id": "d08e73da41b0473d83ea378a57a2fa1f",
"type": "state_machine_state",
"attributes": {
"technicalName": "completed",
"name": "Completed",
"stateMachineId": "7553ad2630044fa589d786135d5000ad",
"customFields": null,
"createdAt": "2020-06-05T14:23:30.482+02:00",
"updatedAt": null,
"translated": {
"name": "Completed",
"customFields": []
},
"apiAlias": null
},
"meta": null
}
]
With the query below I get all three elements
$..[?(#.type == 'state_machine_state')]
I just can't manage to select only the first level elements.
Could anyone please help?

Some implementations will allow you to select several items, but you're not going to be able to get the values with their keys.
For example, if you do
$..[?(#.type == 'state_machine_state')['id','attributes']
You'll just get a result set that contains all of the id values and all of the attributes values.
[
"f45aa035eb424d26a0529d25b3647c32",
{
"technicalName": "cancelled",
"name": "Cancelled",
"stateMachineId": "7553ad2630044fa589d786135d5000ad",
"customFields": null,
"createdAt": "2020-06-05T14:23:30.503+02:00",
"updatedAt": null,
"translated": {
"name": "Cancelled",
"customFields": []
},
"apiAlias": null
},
"2d24ed4179824dbe92eee2f3d4f885b1",
"d08e73da41b0473d83ea378a57a2fa1f",
{
"technicalName": "completed",
"name": "Completed",
"stateMachineId": "7553ad2630044fa589d786135d5000ad",
"customFields": null,
"createdAt": "2020-06-05T14:23:30.482+02:00",
"updatedAt": null,
"translated": {
"name": "Completed",
"customFields": []
},
"apiAlias": null
}
]
JSON Path isn't designed for transformation. JMES Path might be able to do what you're looking for, but I'm not as familiar with it.

Sometimes it helps to take a step back and think another way.
With this query I get exactly what I want:
$..[?(#.type == 'state_machine_state' && #.attributes)]
The elements I need have attributes, the others don't, so I just check for that in the filter.

Related

Conditional select using jq

I have this below json format, I want to take the list of "id" which satisfies the condition
in this below I want to take the id which has matchers.value as dev-stack and status.state as active
{
"status": "success",
"data": [
{
"id": "b5e7f85d",
"matchers": [
{
"name": "stack",
"value": "dev-stack",
"isRegex": true
}
],
"startsAt": "2020-07-13T07:17:36Z",
"endsAt": "2020-07-15T07:15:44Z",
"updatedAt": "2020-07-13T07:15:59.643692023Z",
"createdBy": "api",
"comment": "Silence",
"status": {
"state": "active"
}
},
{
"id": "1fdaa4b5",
"matchers": [
{
"name": "stack",
"value": "qa-stack",
"isRegex": true
}
],
"startsAt": "2020-07-10T13:19:12Z",
"endsAt": "2020-07-10T13:20:55.510739499Z",
"updatedAt": "2020-07-10T13:20:55.510739499Z",
"createdBy": "api",
"comment": "Silence",
"status": {
"state": "expired"
}
}
]
}
Here is a solution which uses update assignment |=, map and select to update .data.
Note it avoids an undesirable cartesian product if multiple .matchers meet the criteria by using any.
.data |= map(select(
(.matchers | any(.value=="dev-stack")) and (.status.state=="active")
))
Try it online!

How can I select a filtered child document collection when querying a top level document in cosmos db

I'm trying to filter the child documents returned when querying a parent document using the sql api in cosmos db.
For example given this document:
{
"customerName": "Wallace",
"customerReference": 666777,
"orders": [
{
"date": "20181105T00:00:00",
"amount": 118.84,
"description": "Laptop Battery"
},
{
"date": "20181105T00:00:00",
"amount": 81.27,
"description": "Toner"
},
{
"date": "20181105T00:00:00",
"amount": 55.12,
"description": "Business Cards"
},
{
"date": "20181105T00:00:00",
"amount": 281.00,
"description": "Espresso Machine"
}]
}
I would like to query the customer to retrieve the name, reference and orders over 100.00 to produce a results like this
[{
"customerName": "Wallace",
"customerReference": 666777,
"orders": [
{
"date": "20181105T00:00:00",
"amount": 118.84,
"description": "Laptop Battery"
},
{
"date": "20181105T00:00:00",
"amount": 281.00,
"description": "Espresso Machine"
}]
}]
the query I have so far is as follows
SELECT c.customerName, c.customerReference, c.orders
from c
where c.customerReference = 666777
and c.orders.amount > 100
this returns an empty set
[]
and if you remove "and c.orders.amount > 100" it matches the document and returns all orders.
To reproduce this issue I simply set up a new database, added a new collection and copied the json example in as the only document. The index policy is left as the default which I've copied below.
{
"indexingMode": "consistent",
"automatic": true,
"includedPaths": [
{
"path": "/*",
"indexes": [
{
"kind": "Range",
"dataType": "Number",
"precision": -1
},
{
"kind": "Range",
"dataType": "String",
"precision": -1
},
{
"kind": "Spatial",
"dataType": "Point"
}
]
}
],
"excludedPaths": []
}
Cosmos DB doesn't support the deep filtering in the way I attempted in my original query.
To achieve the results described you need to use a subquery using a combination of ARRAY and VALUE as follows:
SELECT
c.customerName,
c.customerReference,
ARRAY(SELECT Value ord from ord in c.orders WHERE ord.amount > 100) orders
from c
where c.customerReference = 666777
note the use of 'ord' - 'order' is a reserved word.
The query then produces the correct result - eg
[{
"customerName": "Wallace",
"customerReference": 666777,
"orders": [
{
"date": "20181105T00:00:00",
"amount": 118.84,
"description": "Laptop Battery"
},
{
"date": "20181105T00:00:00",
"amount": 281.00,
"description": "Espresso Machine"
}
]
}]

Symfony Return child objects depend of some property

Im using Symfony 4 + Api Platform. I have an entity (Insurance) that it is relationed with another entity (MediaObject). When I try to GET some item of Insurance, it is returning all the MediaObjects items that they are relationed with it. However, I dont want to return all the MediaObjects. I need MediaObjects where deletedAt is null.
How can I fix that?
I have a DoctrineExtension where I coded:
$queryBuilder->join(sprintf('%s.mediaObjects', $rootAlias), 'mo');
$queryBuilder->andWhere(sprintf('%s.deletedAt IS NULL', $rootAlias));
$queryBuilder->andWhere('mo.deletedAt IS NULL');
but nothing happens. It is still returning all items.
[
{
"id": 1,
"mediaObjects": [
{
"id": 5,
"mimetype": "image/jpeg",
"type": "INSURANCE",
"createdAt": "2018-07-20T09:36:05+02:00",
"updatedAt": "2018-07-20T09:36:05+02:00",
"deletedAt": "2018-07-20T14:20:34+02:00"
},
{
"id": 10,
"mimetype": "image/jpeg",
"type": "INSURANCE",
"createdAt": "2018-07-20T11:01:38+02:00",
"updatedAt": "2018-07-20T14:04:42+02:00",
"deletedAt": "2018-07-20T14:20:34+02:00"
},
{
"id": 4,
"mimetype": "image/jpeg",
"type": "INSURANCE",
"createdAt": "2018-07-20T09:35:56+02:00",
"updatedAt": "2018-07-20T14:04:00+02:00",
"deletedAt": "2018-07-20T14:15:09+02:00"
},
{
"id": 6,
"mimetype": "image/jpeg",
"type": "INSURANCE",
"createdAt": "2018-07-20T09:36:13+02:00",
"updatedAt": "2018-07-20T14:15:49+02:00",
"deletedAt": null
}
],
"expirationDate": "2018-07-19T08:25:29+02:00",
"policy": "Verduras",
"producerName": "Aseguradoras S.L.",
"contactEmail": "testsingfact+aseguradora1#gmail.com",
"contactPhone": "700000001",
"quantity": 1200,
"type": "CARGO",
"coverageExceptions": "Caidas",
"createdAt": "2018-07-19T10:27:22+02:00",
"updatedAt": "2018-07-19T13:06:31+02:00",
"deletedAt": null
}
]
You should use conditional join and apply filter to the joining collection not to the whole set:
$queryBuilder->join(sprintf('%s.mediaObjects', $rootAlias), 'mo', 'WITH', 'mo.deletedAt IS NULL');
$queryBuilder->andWhere(sprintf('%s.deletedAt IS NULL', $rootAlias));
Keep in mind this query will not return insurance entities that do not have non-deleted media objects because of join. If you want it to also return objects with empty media collection change join to leftJoin

Watson Assistant (Conversation) service behaves differently when created via API versus created in the Browser

We are seeing different behaviour when we create a workspace in the WebInterface versus when we create the same conversation via the API.
The JSON export for the dialognode is the same:
{ "type": "standard",
"title": "SmallTalk: weerbericht",
"output": {
"text": {
"values": [],
"selection_policy": "sequential" } },
"parent": "smalltalk_container",
"context": { "user_weer": "#weerbericht",
"user_location": "#plaatsnamen" },
"metadata": {
"_customization": {
"mcr": false } },
"next_step": { "behavior": "jump_to", "selector": "condition", "dialog_node": "node_33_1519129633532"
},
"conditions": "#ST_weersbericht",
"description": null,
"dialog_node": "node_9_1517408489377",
"previous_sibling": "node_3_1518680265483" },
But the behaviour is different, which can be explained when we look at the UI
there is a difference
This is the UI for the dialogNode created via the browser
This is the UI for the same dialogNode created via the API
One difference we found is the Multiple Reponse switch:
It should be OFF (image on the right) and as per the JSON (mcr:false).
But even when we switch it on manually, the context variables don't show.
What should I be looking for in the API to fix this ?
The dialog model for multiple condition responses is that the parent node needs to be either standard dialog node or frame. Now when adding a multiple condition response to this node (and hence making an MCR node out of that parent node) you need to add a dialog node with "type":"response_condition" under this node.
This is a way how to create multiple condition responses through the api.
To give you and example to create MCR node:
The JSON of dialog nodes that need to pushed through the API will look like:
{
"type": "standard",
"title": "mcr node",
"output": {
},
"parent": null,
"context": null,
"metadata": {
"_customization": {
"mcr": true
}
},
"next_step": null,
"conditions": "#book_flight",
"digress_in": "does_not_return",
"description": null,
"dialog_node": "node_8_1525086089064",
"digress_out": "allow_all",
"previous_sibling": null
},
{
"type": "response_condition",
"title": null,
"output": {
"text": {
"values": ["I see city entity!"]
}
},
"parent": "node_8_1525086089064",
"context": null,
"metadata": {
},
"next_step": null,
"conditions": "#city",
"description": null,
"dialog_node": "node_9_1525086100114",
"previous_sibling": null
},
{
"type": "response_condition",
"title": null,
"output": {
"text": {
"values": ["I don't see anything."]
}
},
"parent": "node_8_1525086089064",
"context": null,
"metadata": {
},
"next_step": null,
"conditions": "anything_else",
"description": null,
"dialog_node": "node_10_1525086122332",
"previous_sibling": "node_9_1525086100114"
}

How to validated pointer in json.net?

Hello I have the following scenario:
JSON object:
{
"$id": "1",
"someProp": "123",
"children": [{
"$id": "2",
"$type": "ClassB",
"Parent": {
"$ref": "1"
}
}]
}
JSON schema :
{
"id": "ClassA",
"required": true,
"type": [
"object",
"null"
],
"properties": {
"someProp": {
"required": true,
"type": [
"string",
"null"
]
},
"children": {
"id": "List<Child>",
"required": true,
"type": [
"array",
"null"
],
"items": {
"id": "Child",
"type": [
"object",
"null"
],
"properties": {
"id": {
"required": true,
"type": "integer"
},
"parent": {
"$ref": "ClassA"
}
}
}
}
}
}
I have a complex object who has reference loops, so I have configured json.net to make reference when the object is serialized. Everything is working as expected I can serialize and deserialize the object, but when I am validating the JSON object with the above schema I got the following error :
Required properties are missing from object : "someProp", path :
object.Children[0].parent
And that is correct how can make the schema look at the reference JSON object ?
Problem is with the "id" property of an object inside children array
"properties": {
"id": {
"required": true,
"type": "integer"
},
"parent": {
"$ref": "ClassA"
}
}
You are saying id requires to have property "id" and you don't have that property inside object, either changes "id" to "$id" or remove it from property list to satisfy schema.
"properties": {
"$id": {
"required": true,
"type": "integer"
},
"parent": {
"$ref": "ClassA"
}
}
Also make sure you have "id" / "$id" integer value, i.e.
"$id":2 not "$id":"2"

Resources