Add values to a JSON array if outer array's name == 'something' - jq

I'm passing a JSON object to jq and want to add extra objects to an inner array ('accessories') if its parent array ('platforms') matches a certain name.
Here's my source JSON:
{
"bridge": {
"name": "Homebridge",
"port": 51395
},
"accessories": [],
"platforms": [
{
"name": "Config",
"port": 8581,
"platform": "config"
},
{
"platform": "homebridge-cbus.CBus",
"name": "CBus",
"client_ip_address": "127.0.0.1",
"accessories": [
{
"values": "existing"
}
]
}
]
}
This works beautifully:
jq '.platforms[1].accessories += [{ "values" : "NEW" }]'
... but of course it's poor form to expect platforms[1] to always the be array I want to append to, so I set about trying to form the right syntax for a search or if/then/else to only act on the .name of the appropriate one.
I thought this was my solution:
jq '.platforms[] | if ( .name=="CBus" ) then .accessories += [{ "values" : "NEW" }] else . end'
... until I realised it was only passing the 'platforms' through and eating the 'bridge' object and empty outer 'accessories' array, which I need to retain.
My issue looks to be similar to JQ | Updating array element selected by `select`, but I've tried LOTS of combinations but just can't break through.
Edit: Here's the correct JQPlay I've been working with:
https://jqplay.org/s/dGDswqAEte
Thanks for any help.

That's a good attempt. The key here is to use the select() function to identify the object you are going to update and overwrite the overall array using |= operator, i.e.
.platforms |= ( map(select(.name == "CBus").accessories += [{ "values" : "NEW" }] ) )
For the snippet in your jq-play link (now removed), you need to do
.gcp_price_list."CP-COMPUTEENGINE-OS"
|= with_entries(select(.value.cores == "shared").value.cores = "0.5")
Or if you want to be even more specific, and keep the entry in gcp_price_list configurable, do
.gcp_price_list |=
with_entries (
select(.key == "CP-COMPUTEENGINE-OS").value |=
with_entries(
select(.value.cores == "shared").value.cores = "0.5") )

Related

Adding key name to value using jq

I am trying to dynamically assign the key name as its value in my json
This is the json i am using:
{
"test1": "",
"test2": "",
"test3": ""
}
the result i would like to obtain looks like this:
{
"test1": "test1",
"test2": "test2",
"test3": "test3"
}
I am not familiar with jq and the closest result i got is using:
keys[] as $key | {"\($key)": "\($key)"} | .
here is the output:
{
"test1": "test1"
}
{
"test2": "test2"
}
{
"test3": "test3"
}
with_entries lets you manipulate .key and .value for each field. Just set one to the value of the other:
with_entries(.value = .key)
{
"test1": "test1",
"test2": "test2",
"test3": "test3"
}
Demo
Following your approach, you could collect your result objects into an array using the array constructors […] around your filter, and then add up the array's items producing one merged object. (Note that | . can be dropped as it doesn't do anything but reproduce itself, and that the string interpolation "\($key)" is just the same as $key, given $key is a string, which is the case here as object field names are always strings.)
[keys[] as $key | {($key): $key}] | add
Demo
You may also entirely drop the use of variables as there is no other context interfering:
[keys[] | {"\(.)": .}] | add
Demo
And there is a shortcut for patterns like [.[] | …] called map:
keys | map({"\(.)": .}) | add
Demo
Alternatively, you also might want to consider using reduce for an iterative manipulation, and/or keys_unsorted which acts like keys but produces the keys in the original (unsorted) order:
reduce keys_unsorted[] as $key (.; .[$key] = $key)
Demo

Remove multiple entries from an array of objects using jq

I have the following json and want to remove multiple entries from the ebooks array if they are not in the following array ["Pascal", "Python"] (will eventually be dynamic array, this is just for example)
{
"eBooks":[
{
"language":"Pascal",
"edition":"third"
},
{
"language":"Python",
"edition":"four"
},
{
"language":"SQL",
"edition":"second"
}
]
}
was hoping to do something like this, which if it worked would delete last one containing the SQL because it's not in the array, but this doesn't work
jq '.ebooks[] | select ( .language | in(["Pascal", "Python"]))' ebooks.json
You're almost there. Use del, IN and a capital B in eBooks :)
jq 'del(.eBooks[] | select(.language | IN("Pascal", "Python")))' ebooks.json
{
"eBooks": [
{
"language": "SQL",
"edition": "second"
}
]
}
Demo

Terraform: Add item to a DynamoDB Table

What is the correct way to add tuple and key-pair values items to a DynamoDB database via Terraform?
I am trying like this:
resource "aws_dynamodb_table_item" "item" {
table_name = aws_dynamodb_table.dynamodb-table.name
hash_key = aws_dynamodb_table.dynamodb-table.hash_key
for_each = {
"0" = {
location = "Madrid"
coordinates = [["lat", "40.49"], ["lng", "-3.56"]]
visible = false
destinations = [0, 4]
}
}
item = <<ITEM
{
"id": { "N": "${each.key}"},
"location": {"S" : "${each.value.location}"},
"visible": {"B" : "${each.value.visible}"},
"destinations": {"L" : [{"N": "${each.value.destinations}"}]
}
ITEM
}
And I am getting the message:
each.value.destinations is tuple with 2 elements
│
│ Cannot include the given value in a string template: string required.
I also have no clue on how to add the coordinates variable.
Thanks!
List should be something like that :
"destinations": {"L": [{ "N" : 1 }, { "N" : 2 }]}
You are trying to pass
"destinations": {"L": [{ "N" : [0,4] }]}
Also you are missing the last } in destinations key
TLDR: I think the problem here is that you are trying to put L(N) - i.e. a list of numeric values, while your current Terraform code tries to put all the destinations into one N/number.
Instead of:
[{"N": "${each.value.destinations}"}]
you need some iteration over destinations and building a {"N": ...} of them.
"destinations": {"NS": ${jsonencode(each.value.destinations)}}
Did the trick!

Combine orderByPriority with equalTo

I have a dataset like this:
[
{
"projectId": "fdsFDSFaSdA",
"teamId": "ASDasdASDsada"
...
},
{
"projectId": "DSF432afdsf",
"teamId": "fdsASfsdasdd"
...
},
...
]
I nead to select objects from this list sometimes by projectId, sometimes by teamId.
I know that this is possible like so:
ref.orderByChild('key').equalTo(value)
But the problem is that I need to order by priority.
I see that equalTo() takes two parameters:
equalTo(value, [key])
I tried like so but it doesn't work:
ref.orderByPriority().equalTo(value, 'key')
How can I make it work?

Query to get exact matches of Elastic Field with multile values in Array

I want to write a query in Elastic that applies a filter based on values i have in an array (in my R program). Essentially the query:
Matches a time range (time field in Elastic)
Matches "trackId" field in Elastic to any value in array oth_usr
Return 2 fields - "trackId", "propertyId"
I have the following primitive version of the query but do not know how to use the oth_usr array in a query (part 2 above).
query <- sprintf('{"query":{"range":{"time":{"gte":"%s","lte":"%s"}}}}',start_date,end_date)
view_list <- elastic::Search(index = "organised_recent",type = "PROPERTY_VIEW",size = 10000000,
body=query, fields = c("trackId", "propertyId"))$hits$hits
You need to add a terms query and embed it as well as the range one into a bool/must query. Try updating your query like this:
terms <- paste(sprintf("\"%s\"", oth_usr), collapse=", ")
query <- sprintf('{"query":{"bool":{"must":[{"terms": {"trackId": [%s]}},{"range": {"time": {"gte": "%s","lte": "%s"}}}]}}}',terms,start_date,end_date)
I'm not fluent in R syntax, but this is raw JSON query that works.
It checks whether your time field matches given range (start_time and end_time) and whether one of your terms exact matches trackId.
It returns only trackId, propertyId fields, as per your request:
POST /indice/_search
{
"_source": {
"include": [
"trackId",
"propertyId"
]
},
"query": {
"bool": {
"must": [
{
"range": {
"time": {
"gte": "start_time",
"lte": "end_time"
}
}
},
{
"terms": {
"trackId": [
"terms"
]
}
}
]
}
}
}

Resources