API Platform: Change embedded sub-resources to theirs #id - symfony

I'm using Symfony 4.3 and API Platform 2.4.
In my API there are resource 'groups' and related sub-resource 'phones':
{
"#context": "/contexts/groups",
"#id": "/groups/7116",
"#type": "groups",
"id": 7116,
"name": "Standard Test",
"description": "",
"phones": {
"7848412": {
"#id": "/phones/7848412",
"#type": "phones",
"id": 7848412,
"phone": "+412344545656",
"a": "o2",
"b": "",
"c": "",
"d": "",
"e": ""
}
}
Resources YAMLs:
entities\ClientPhoneGroup:
shortName: 'groups'
description: "Phone's group"
collectionOperations:
post:
denormalization_context:
groups: ['write']
itemOperations:
get: ~
put:
denormalization_context:
groups: ['write']
delete: ~
attributes:
normalization_context:
groups: ['read']
security: "is_granted('IS_AUTHENTICATED_FULLY')"
subresource_operations:
phone_get_subresource:
method: 'GET'
properties:
id:
identifier: true
phones:
subresource:
resourceClass: 'entities\ClientPhone'
collection: false
and
entities\ClientPhone:
shortName: 'phones'
description: "Phones list by group"
collectionOperations:
post:
path: /groups/{group_id}/phones
requirements:
group_id: '\d+'
denormalization_context:
groups: ['write']
itemOperations:
get: ~
put:
denormalization_context:
groups: ['write']
delete: ~
attributes:
normalization_context:
groups: ['read']
security: "is_granted('IS_AUTHENTICATED_FULLY') "
serializers YAMLs:
entities\ClientPhoneGroup:
attributes:
id:
groups: ['read']
name:
groups: ['read', 'write']
description:
groups: ['read', 'write']
phones:
groups: ['read']
and
entities\ClientPhone:
attributes:
id:
groups: ['read']
phone:
groups: ['read', 'write', 'edit']
a:
groups: ['read', 'write', 'edit']
b:
groups: ['read', 'write', 'edit']
c:
groups: ['read', 'write', 'edit']
d:
groups: ['read', 'write', 'edit']
e:
groups: ['read', 'write', 'edit']
How to change embeded phones list to '/groups/7116/phones' in groups
resource?
How to add link to 'group' resource (e.g. /groups/7116) to
the phone sub-resource?

Answer Question 2.
Remove normalization_context:groups: ['read'] from entities\ClientPhone so when you will call a GET group resource api, phone sub-resource will have IRI instead of all fields.

Related

How to select specific key after filtering the data using YQ

myres.json
[
{
"id": "id_1",
"name": "default",
},
{
"id": "id_2",
"name": "name2",
},
{
"id": "id_3",
"name": "name3",
}
]
I waanted to get only name whose id = 3
I am able to filter out the object using yq following command
yq -r '.[] | select(.id == "id_3" )' myres.json
and output is
{
"id": "id_3",
"name": "name3",
}
I tried with with_entries, from_entries but no luck.
Thanks in advance !!
I am using kislyuk/yq 2.14.1 version
As Per #Inian, I made few changes in query as follows according to my requirements.
yq -r '.[] | select(.id=="id_2").name' s.txt

Understanding fold() and its impact on gremlin query cost in Azure Cosmos DB

I am trying to understand query costs in Azure Cosmos DB
I cannot figure out what is the difference in the following examples and why using fold() lowers the cost:
g.V().hasLabel('item').project('itemId', 'id').by('itemId').by('id')
which produces the following output:
[
{
"itemId": 14,
"id": "186de1fb-eaaf-4cc2-b32b-de8d7be289bb"
},
{
"itemId": 5,
"id": "361753f5-7d18-4a43-bb1d-cea21c489f2e"
},
{
"itemId": 6,
"id": "1c0840ee-07eb-4a1e-86f3-abba28998cd1"
},
....
{
"itemId": 5088,
"id": "2ed1871d-c0e1-4b38-b5e0-78087a5a75fc"
}
]
The cost is 15642 RUs x 0.00008 $/RU = 1.25$
g.V().hasLabel('item').project('itemId', 'id').by('itemId').by('id').fold()
which produces the following output:
[
[
{
"itemId": 14,
"id": "186de1fb-eaaf-4cc2-b32b-de8d7be289bb"
},
{
"itemId": 5,
"id": "361753f5-7d18-4a43-bb1d-cea21c489f2e"
},
{
"itemId": 6,
"id": "1c0840ee-07eb-4a1e-86f3-abba28998cd1"
},
...
{
"itemId": 5088,
"id": "2ed1871d-c0e1-4b38-b5e0-78087a5a75fc"
}
]
]
The cost is 787 RUs x 0.00008$/RU = 0.06$
g.V().hasLabel('item').values('id', 'itemId')
with the following output:
[
"186de1fb-eaaf-4cc2-b32b-de8d7be289bb",
14,
"361753f5-7d18-4a43-bb1d-cea21c489f2e",
5,
"1c0840ee-07eb-4a1e-86f3-abba28998cd1",
6,
...
"2ed1871d-c0e1-4b38-b5e0-78087a5a75fc",
5088
]
cost: 10639 RUs x 0.00008 $/RU = 0.85$
g.V().hasLabel('item').values('id', 'itemId').fold()
with the following output:
[
[
"186de1fb-eaaf-4cc2-b32b-de8d7be289bb",
14,
"361753f5-7d18-4a43-bb1d-cea21c489f2e",
5,
"1c0840ee-07eb-4a1e-86f3-abba28998cd1",
6,
...
"2ed1871d-c0e1-4b38-b5e0-78087a5a75fc",
5088
]
]
The cost is 724.27 RUs x 0.00008 $/RU = 0.057$
As you see, the impact on the cost is tremendous.
This is just for approx. 3200 nodes with few properties.
I would like to understand why adding fold changes so much.
I was trying to reproduce your example, but unfortunately have opposite results (500 vertices in Cosmos):
g.V().hasLabel('test').values('id')
or
g.V().hasLabel('test').project('id').by('id')
gave respectively
86.08 and 91.44 RU, while same queries followed by fold() step resulted in 585.06 and
590.43 RU.
This result I got seems fine, as according to TinkerPop documentation:
There are situations when the traversal stream needs a "barrier" to
aggregate all the objects and emit a computation that is a function of
the aggregate. The fold()-step (map) is one particular instance of
this.
Knowing that Cosmos charge RUs for both number of accessed objects and computations that are done on those obtained objects (fold in this particular case), higher costs for fold is as expected.
You can try to run executionProfile() step for your traversal, which can help you to investigate your case. When I tried:
g.V().hasLabel('test').values('id').executionProfile()
I got 2 additional steps for fold() (same parts of output omitted for brevity), and this ProjectAggregation is where the result set was mapped from 500 to 1:
...
{
"name": "ProjectAggregation",
"time": 165,
"annotations": {
"percentTime": 8.2
},
"counts": {
"resultCount": 1
}
},
{
"name": "QueryDerivedTableOperator",
"time": 1,
"annotations": {
"percentTime": 0.05
},
"counts": {
"resultCount": 1
}
}
...

Use jq to combine two arrays of objects on a certain key

I am trying to use jq to solve this problem.
Suppose I have the following object
{
"listA": [
{
"id": "12345",
"code": "001"
}
]
"listB": [
{
"id": "12345",
"prop": "AABBCC"
}
]
}
In reality my two lists are longer, but the id isn't repeated within each list.
How may I combine the two lists into a single list where each item is an object with the non-id properties for the given id are collected into a single object?
For example, from the object above, I'd like the following:
{
"listC" : [
{
"id": "12345",
"code": "001",
"prop": "AABBCC"
}
]
}
A simple way would be to concatenate the arrays, group the elements by id and map each group into a single object using add;
jq '.listA+.listB | group_by(.id) | map(add)' test.json
If there may be more than two arrays you need to merge in the file, you could instead use flatten to concatenate all of them.
Test case below
# cat test.json
{
"listA": [
{ "id": "12345", "code": "001" },
{ "id": "12346", "code": "002" }
],
"listB": [
{ "id": "12345", "prop": "AABBCC" }
]
}
# jq 'flatten | group_by(.id) | map(add)' test.json
# or
# jq '.listA+.listB | group_by(.id) | map(add)' test.json
[
{
"id": "12345",
"code": "001",
"prop": "AABBCC"
},
{
"id": "12346",
"code": "002"
}
]
Using group_by entails a sort, which is unnecessary, so if efficiency is a concern, then an alternative approach such as the following should be considered:
INDEX(.listA[]; .id) as $one
| INDEX(.listB[]; .id) as $two
| reduce ($one|keys_unsorted[]) as $k ($two; .[$k] += $one[$k])
| {listC: [.[]] }

Attaching a new volume each time a node group is scaled

Can anyone share any reference template to create a new volume and attach to a new instance each time a deployment for that instance is scaled up?
My template looks like:
node_templates:
key_pair:
...
vol:
...
node_host:
...
relationships:
...
- key_pair
- vol
node:
...
relationships:
- type: cloudify.relationships.contained_in
target: node_host
...
groups:
scale_up_group:
members: [node, node_host, vol]
policies:
auto_scale_up:
type: scale_policy_type
properties:
policy_operates_on_group: true
scale_limit: 6
scale_direction: '<'
scale_threshold: 15
service_selector: cpu.total.user
cooldown_time: 60
triggers:
execute_scale_workflow:
type: cloudify.policies.triggers.execute_workflow
parameters:
workflow: scale
workflow_parameters:
delta: 1
scalable_entity_name: node
scale_compute: true
Courtesy of Trammell from cloudify-user group:
node_templates:
key_pair:
type: cloudify.openstack.nodes.KeyPair
...
floating_ip:
type: cloudify.openstack.nodes.FloatingIP
...
vol:
type: cloudify.openstack.nodes.Volume
...
node_host:
type: cloudify.openstack.nodes.Server
...
relationships:
- type: cloudify.openstack.server_connected_to_keypair
target: keypair
- type: cloudify.openstack.server_connected_to_floating_ip
target: floating_ip
- type: cloudify.relationships.depends_on
target: vol
node:
type: custom.node.type
...
relationships:
- type: cloudify.relationships.contained_in
target: node_host
...
groups:
scale_vm:
members: [node, node_host, floating_ip, vol]
scale_up_group:
members: [node, node_host, floating_ip, vol]
policies:
auto_scale_up:
type: scale_policy_type
properties:
policy_operates_on_group: true
scale_limit: 6
scale_direction: '<'
scale_threshold: 15
service_selector: cpu.total.user
cooldown_time: 60
triggers:
execute_scale_workflow:
type: cloudify.policies.triggers.execute_workflow
parameters:
workflow: scale
workflow_parameters:
delta: 1
scalable_entity_name: scale_vm
scale_compute: true
policies:
scale_vm_policy:
type: cloudify.policies.scaling
properties:
default_instances: 1
targets: [scale_vm]
Ref: https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!topic/cloudify-users/TPepGofpSBU

How do I select multiple fields in jq?

My input file looks something like this:
{
"login": "dmaxfield",
"id": 7449977,
...
}
{
"login": "dmaxfield",
"id": 7449977,
...
}
I can get all the login names with this : cat members | jq '.[].login'
but I have not been able to crack the syntax to get both the login and id?
You can use jq '.[] | .login, .id' to obtain each login followed by its id.
This works for me:
> echo '{"a":1,"b":2,"c":3}{"a":1,"b":2,"c":3}' | jq '{a,b}'
{
"a": 1,
"b": 2
}
{
"a": 1,
"b": 2
}
Just provide one more example here (jq-1.6):
Walk through an array and select a field of an object element and a field of object in that object
echo '[{"id":1, "private_info": {"name": "Ivy", "age": 18}}, {"id":2, "private_info": {"name": "Tommy", "aga": 18}}]' | jq ".[] | {id: .id, name: .private_info.name}" -
{
"id": 1,
"name": "Ivy"
}
{
"id": 2,
"name": "Tommy"
}
Without the example data:
jq ".[] | {id, name: .private_info.name}" -
.[]: walk through an array
{id, name: .private_info.name}: take .id and .private_info.name and wrap it into an object with field name "id" and "name" respectively
In order to select values which are indented to different levels (i.e. both first and second level), you might use the following:
echo '[{"a":{"aa":1,"ab":2},"b":3,"c":4},{"a":{"aa":5,"ab":6},"b":7,"c":8}]' \
| jq '.[]|[.a.aa,.a.ab,.b]'
[
1,
2,
3
]
[
5,
6,
7
]

Resources