Return object with dynamic keys in AQL - arangodb

Can I return something like:
{
"c/12313" = 1,
"c/24223" = 2,
"c/43423" = 3,
...
}
from an AQL query? The idea is something like (this non-working code):
for c in my_collection
return { c._id : c.sortOrder }
where sortOrder is some property on my documents.

Yes, it is possible to have dynamic attribute names:
LET key = "foo"
LET value = "bar"
RETURN { [ key ]: value } // { "foo": "bar" }
An expression to compute the attribute key has to be wrapped in [ square brackets ], like in JavaScript.
This doesn't return quite the desired result however:
FOR c IN my_collection
RETURN { [ c._id ]: c.sortOrder }
[
{ "c/12313": 1 },
{ "c/24223": 2 },
{ "c/43423": 3 },
...
]
To not return separate objects for every key, MERGE() and a subquery are required:
RETURN MERGE(
FOR c IN my_collection
RETURN { [ c._id ]: c.sortOrder }
)
[
{
"c/12313": 1,
"c/24223": 2,
"c/43423": 3,
...
}
]

Related

How to count a field if value is not null in elasticsearch

I have indexed some documents in ElasticSearch.
Short view looks like this:
{
"tenant_id":"abcd1234"
"provider_id":"3456"
.
.
.
"doctor_summary": ["line1", "line2", "line3"] OR it could be null.
}
I want to calculate this list as 1 if not null,
query_template = {
"bool":{
"must":[
{"term":{"tenant_id.keyword":tenant_id}},
{"term":{"provider_id.keyword":provider_id}},
{"range":{"visit_date":{"gte":from_date,"lte":to_date}}},
],
"filter":[]
}
}
aggs_query = {
"doctor_summary_count":{
"value_count":{"field":"doctor_summary.keyword"}
}
}
res = CLIENT.search(index = config['elasticsearch']['abcd'],
query = query_template,
size = 10000,
aggs = aggs_query)
After calling this aggregation query, it gives result as ( size of the list * total doctor_summary field).
For example: the result of above query on above document should be 1. (As it is not null).
But it gives as 3(because list contains 3 lines.)
You can use exist query in aggregation with filter aggregation.
Query:
{
"aggs": {
"count": {
"filter": {
"exists": {
"field": "doctor_summary.keyword"
}
}
}
}
}
Response:
"aggregations" : {
"count" : {
"doc_count" : 1
}
}

How to use ellipsis (…) in nested for loop

I see this error "If duplicates are expected, use the ellipsis (...) after the value expression to enable grouping by key."
locals {
key_id = {
for x in var.security_rules :
"${x.type}" => x}
}
Is it possible to use ellipsis in a nested for this loop and how can i do it?
The error message means that var.security_rules has multiple items with the same type. For example:
variable "security_rules" {
default = [
{
type = "a"
},
{
type = "b"
},
{
type = "a"
}
]
}
We can see that there are at least 2 items with the same type, which wont be accepted as key in map. What we can do here is to group the items with the same type. This is exactly what ellipsis (...) will accomplish. So:
locals {
key_id = {
for x in var.security_rules : "${x.type}" => x... }
}
The value of key_id in this example will be:
key_id = {
"a" = [
{
"type" = "a"
},
{
"type" = "a"
},
]
"b" = [
{
"type" = "b"
},
]
}

Default values on nested maps in Groovy

I have a JSON configuration file that I want to read with groovy
this file has "defaults" in case one key would be missing because no specific configuration has been added.
json
{
"presets": {
"default": "preset_default",
"Team1":{
"AppName1":{
"Component1": "preset_team1App1Comp1",
"default" : "preset_team1App1Default"
},
"AppName2":{
"Component1": "preset_team1App2Comp1",
"Component2": "preset_team1App2Comp2"
},
"default" : "preset_team1Default"
},
"Team2":{
"AppName1":{
"Component1": "preset_team2App1Comp1"
}
}
}
}
What would be the most groovy way to search for the value and falling back to the outer most "default" key?
here's how I implemented it but I'm not sure this would work:
if (presets[appTeam])
if (presets[appTeam][appName])
if (presets[appTeam][appName][compName])
this.preset = presets[appTeam][appName][compName]
else
this.preset = presets[appTeam][appName]['default']
else
this.preset = presets[appTeam]['default']
else
this.preset = presets['default']
Thank you in advance
One way would be to use "inject" to walk along your keys, and keep track of the latest default seen... Something like this:
def value(Map presets, String... keys) {
keys.inject([pos: presets, result: presets.default]) { latest, current ->
def node = latest.pos[current]
if (node instanceof Map) {
[pos: node, result: node.default ?: latest.result]
} else if (node instanceof String) {
[pos: node, result: node]
} else if (node == null) {
[pos: node, result: latest.result]
} else {
throw new RuntimeException("No idea what to do with a ${node.class.simpleName}")
}
}.result
}
Then you can do (with the above example)
// Defaults
assert value(presets, 'TeamUnknown', "AppName2", "Component14") == 'preset_default'
assert value(presets, 'Team1', "AppName2", "Component14") == 'preset_team1Default'
// Values
assert value(presets, 'Team1', "AppName2", "Component1") == 'preset_team1App2Comp1'
another way
def value(presets, team, app, compt) {
def defkey = 'default'
return presets.get(team)?.get(app)?.get(compt) ?:
presets.get(team)?.get(app)?.get(defkey) ?:
presets.get(team)?.get(defkey) ?:
presets.get(defkey)
}
assert value(presets, 'TeamUnknown', "AppName2", "Component14") == 'preset_default'
assert value(presets, 'Team1', "AppName2", "Component14") == 'preset_team1Default'
assert value(presets, 'Team1', "AppName2", "Component1") == 'preset_team1App2Comp1'
A simple generic recursion would help:
def input = new groovy.json.JsonSlurper().parseText '''{
"presets": {
"default": "preset_default",
"Team1":{
"AppName1":{
"Component1": "preset_team1App1Comp1",
"default" : "preset_team1App1Default"
},
"AppName2":{
"Component1": "preset_team1App2Comp1",
"Component2": "preset_team1App2Comp2"
},
"default" : "preset_team1Default"
},
"Team2":{
"AppName1":{
"Component1": "preset_team2App1Comp1"
}
}
}
}'''
def findRecursive
findRecursive = { json, List keys, List defaults = [] ->
if( !json || ( json in String ) || !keys ) return json
if( json.default ) defaults << json.default
findRecursive json[ keys.remove( 0 ) ] ?: defaults.last(), keys, defaults
}
assert 'preset_team1App1Comp1' == findRecursive( input.presets, [ 'Team1', 'AppName1', 'Component1' ] )
assert 'preset_team2App1Comp1' == findRecursive( input.presets, [ 'Team2', 'AppName1', 'Component1' ] )
assert 'preset_team1Default' == findRecursive( input.presets, [ 'Team1', 'AppName3', 'Component1' ] )
assert 'preset_default' == findRecursive( input.presets, [ 'Team3' ] )
assert 'preset_default' == findRecursive( input.presets, [ 'Team2', 'AppName2', 'Component1' ] )

Groovy JsonBuilder objects

I'm having some trouble with my JsonBuilder. I'd like the output to look like the following:
{
"appointmentCheckResult": [
{
"itexxmCode": "98765432",
" needAppointmentCheckFlag ": "Y"
},
{
"itemCode": "98765433",
"needAppointmentCheckFlag": "N"
}
]
}
what I get is :
{
"appointmentCheckResult": {
"xxx": [
{
"itemCode": "12345",
"needAppointmentCheckFlag": "Y"
},
{
"itemCode": "5678902",
"needAppointmentCheckFlag": "Y"
}
]
}
}
The code is shown below:
import groovy.json.*
def json = new JsonBuilder()
def itemCode = ['12345', '5678902']
def needFlag = 'Y'
json.appointmentCheckResult{xxx([itemCode].transpose().collect {[itemCode:it[0], needAppointmentCheckFlag:needFlag]})}
println JsonOutput.prettyPrint(json.toString())
How can I get rid of the XXX and the "{" which in front of XXX?
No idea how you're expecting to get the Y and N in the output, or itexxmCode as a key... But assuming they're typos in the expected output, you need something like:
json {
appointmentCheckResult(
[itemCode].transpose().collect {
[itemCode: it[0], needAppointmentCheckFlag: needFlag]
}
)
}

Return Nested Key in Groovy

I am trying to determine the best way to return nested key values using groovy. If I have a map:
def map = [
OrganizationName: 'SampleTest',
Address: [
Street: '123 Sample St',
PostalCode: '00000',
]
]
Is there a way to return all of the keys? OrganizationName, OrganizationURL, Address.Street, Address.PostalCode? If I didn't have an map within a map I could use map.keySet() as String[]. Should I just loop through each key and see if it is an instanceof another map?
The Groovy libraries don't provide a method for this, but you can write your own. Here's an example that you can copy-paste into the Groovy console
List<String> getNestedMapKeys(Map map, String keyPrefix = '') {
def result = []
map.each { key, value ->
if (value instanceof Map) {
result += getNestedMapKeys(value, keyPrefix += "$key.")
} else {
result << "$keyPrefix$key"
}
}
result
}
// test it out
def map = [
OrganizationName: 'SampleTest',
Address: [
Street: '123 Sample St',
PostalCode: '00000',
]
]
assert ['OrganizationName', 'Address.Street', 'Address.PostalCode'] == getNestedMapKeys(map)
Use Following generic recursion Method To generate the list of all nested map keys
def getListOfKeys(def map, String prefix,def listOfKeys){
if(map instanceof Map){
map.each { key, value->
if(prefix.isEmpty()){
listOfKeys<<key
}else{
listOfKeys<< prefix+"."+key
}
if(value instanceof List){
List list = value
list.eachWithIndex { item, index ->
if(prefix.isEmpty()){
getListOfKeys(item, key+"["+index+"]",listOfKeys)
}else{
getListOfKeys(item, prefix+"."+key+"["+index+"]",listOfKeys)
}
}
}else if(value instanceof Map){
if(prefix.isEmpty()){
getListOfKeys(value, key,listOfKeys)
}else{
getListOfKeys(value, prefix+"."+key,listOfKeys)
}
}
}
}
}
call above method as follows
def void findAllKeysInMap(){
Map map = [ "fields":[
"project":
[
"key": "TP"
],
"summary": "Api Testing Issue.",
"description": "This issue is only for api testing purpose",
"issuetype": [
"name": ["Bug":["hello":[["saurabh":"gaur","om":"prakash"], ["gaurav":"pandey"], ["mukesh":"mishra"]]]]
]
]
]
def listOfKeys=[]
getListOfKeys(map, '', listOfKeys)
println "listOfKeys>>>"+listOfKeys
}
output:
listOfKeys>>>[fields, fields.project, fields.project.key, fields.summary, fields.description, fields.issuetype, fields.issuetype.name, fields.issuetype.name.Bug, fields.issuetype.name.Bug.hello, fields.issuetype.name.Bug.hello[0].saurabh, fields.issuetype.name.Bug.hello[0].om, fields.issuetype.name.Bug.hello[1].gaurav, fields.issuetype.name.Bug.hello[2].mukesh]
There's no such method You're looking for in groovy. You need to do it using instanceof and probably a recursive method.
Slightly shorter:
String key = 'Address.Street'
key.split('\\.').inject(yourMap) {map, path -> map[path]}
If you can't guarantee that the path exists and is complete (say, if you tried to access OrganizationName.id) you'll need to add some safeguards (check that map is not null, and that it's really a Map)

Resources