How to group by parent and collect all property values of child in gremlin? - gremlin

I want to collect all shows and their associated genres together. GENRES are child relationship of SHOWS
Sample gemlin graph
So that the output is something similar to:
"1" [a,b]
"2" [c,d]
Sample graph: https://gremlify.com/x8i8stszn2

You can accomplish this using the project() step within Gremlin like this:
g.V("2789").out('WATCHED').hasLabel('SHOW').
project('show', 'genre').
by('NAME').
by(out('HAS_GENRE').values('NAME').fold())
This will return your data formatted like this this:
[
{
"show": 1,
"genre": [
"a",
"b"
]
},
{
"show": 2,
"genre": [
"c",
"d"
]
}
]

Related

extract value from JSON object using SQLite and the json_tree function

I have a table (named, patrons) that contains a column (named, json_patron_varfields) of JSON data--an array of objects that looks something like this:
[
{
"display_order": 1,
"field_content": "example 1",
"name": "Note",
"occ_num": 0,
"varfield_type_code": "x"
},
{
"display_order": 2,
"field_content": "example 2",
"name": "Note",
"occ_num": 1,
"varfield_type_code": "x"
},
{
"display_order": 3,
"field_content": "some field we do not want",
"occ_num": 0,
"varfield_type_code": "z"
}
]
What I'm trying to do is to target the objects that contain the key named varfield_type_code and the value of x which I've been able to do with the following query:
SELECT
patrons.patron_record_id,
json_extract(patrons.json_patron_varfields, json_tree.path)
FROM
patrons,
json_tree(patrons.json_patron_varfields)
WHERE
json_tree.key = 'varfield_type_code'
AND json_tree.value = 'x'
My Question is... how do I extract (or even possibly filter on) the values of the field_content keys from the objects I'm extracting?
I'm struggling with the syntax of how to do that... I was thinking it could be as simple as using json_extract(patrons.json_patron_varfields, json_tree.path."field_content") but that doesn't appear to be correct..
You can concat to build the string
json_tree.path || '.field_content'
With the structure you've given - you can also use json_each() instead of json_tree() which may simplify things.
extract:
SELECT
patrons.patron_record_id,
json_extract(value, '$.field_content')
FROM
patrons,
json_each(patrons.json_patron_varfields)
WHERE json_extract(value, '$.varfield_type_code') = 'x'
filter:
SELECT
patrons.patron_record_id,
value
FROM
patrons,
json_each(patrons.json_patron_varfields)
WHERE json_extract(value, '$.varfield_type_code') = 'x'
AND json_extract(value, '$.field_content') = 'example 2'

JQ how to combine heterogeneous objects into one array?

How could I use JQ to parse the following JSON object and produce the output below?
JSON Input:
{
"key1": {
"a": "A"
},
"key2": {
"b": "123"
},
"key3": {
"c": ["C1", "C2"]
}
}
Desired Output:
[
"a": "A",
"b": 123,
"c": "C1",
"c": "C2"
]
The following program produces the output shown below it:
def q: "\"\(.)\"";
.[]
| to_entries[]
| (.key|q) as $k
| if .value|type == "array"
then .value[] | "\($k): \(q)"
else "\($k): \(.value|q)"
end
Output:
"a": "A"
"b": "123"
"c": "C1"
"c": "C2"
This, or something very much like it, should be sufficient for using in a bash script, but if you really want the format shown in the Q, feel free to fiddle around. A more useful way to spend your time would probably be to read up on jq-bash interoperability, e.g. here on SO:
Is there a way to output jq into multiple variables for bash script?
get field from json and assign to variable in bash script?
... and many others.

Dynamodb SK range key is not returning data as expected

I am using the below query to get from DB (GSI):
results = table.query(
IndexName="Table-ID-index",
KeyConditionExpression=Key("id").eq(id),
)
However, my data is not sort based on the range key set with the GSI. Sample response I am getting with above query:
{
"value": "test1",
"sk": "1#1",
"id": "1"
},
{
"value": "test19",
"sk": "19#19",
"id": "19"
},
{
"value": "test2",
"sk": "2#2",
"id": "2"
}
sk 19 should come after sk 2. Is there anything I have missed in my query?
If memory serves, this is because the strings being stored and sorted in their UTF-8 encoded form. From the documentation:
"DynamoDB collates and compares strings using the bytes of the underlying UTF-8 string encoding. For example, "a" (0x61) is greater than "A" (0x41), and "¿" (0xC2BF) is greater than "z" (0x7A)."

Find an edge that is already connected with vertices to a specific vertex ID, and merge it with the result

Consider facebook search results of the people list scenario. I want to get all the people from the database (hasLabel('person')). For each of these people, I want to know whether the logged in person already have connected and follows. What is the best solution to get this in gremlin (possibly avoiding duplication)?
g.addV('person').property('id',1).as('1').
addV('person').property('id',2).as('2').
addV('person').property('id',3).as('3').
addV('person').property('id',4).as('4').
addE('connected').from('1').to('2').
addE('connected').from('2').to('3').
addE('connected').from('3').to('1').
addE('connected').from('4').to('2').
addE('follows').from('1').to('2').
addE('follows').from('1').to('3').
addE('follows').from('1').to('4').
addE('follows').from('2').to('1').
addE('follows').from('2').to('3').
addE('follows').from('3').to('1').
addE('follows').from('3').to('4').
addE('follows').from('4').to('2').
addE('follows').from('4').to('3').iterate()
For instance, if the logged-in person id is 2, the formatted JSON response will be
[
{
"id": 1,
"follows": true,
"connected": true
},
{
"id": 3,
"follows": true,
"connected": false
},
{
"id": 4,
"follows": false,
"connected": true
}
]
and if the logged-in person id is 4
[
{
"id": 1,
"follows": false,
"connected": false
},
{
"id": 2,
"follows": true,
"connected": true
},
{
"id": 3,
"follows": true,
"connected": false
}
]
Note: The JSON response is provided to understand the outcome, but I just wanted the Gremlin query to get the outcome.
Below is the general pattern you are looking for however based on the script you have listed above and the direction of the edges it's unclear exactly when to return true and when not to.
g.V().
hasLabel('person').
not(has('id', 2)). //find me person 2
project('id', 'follows', 'connected').
by('id').
by(
__.in('follows').
has('id', 2). //traverse all inbound follows edges to find if they go to person 2
fold(). //create an array (empty if nothing)
coalesce(unfold().constant(true), constant(false))). //return true if edge exists, else false
by(
__.out('connected').
has('id', 2).
fold().
coalesce(unfold().constant(true), constant(false)))
Based on the script you provided there is no way to get the answers you asked for. Let's look at just the connected edges.
For vertex 2:
using in() we would get true for 1 and 4 and false for 3
using out() we would get true for 3 and false for 1 and 4
using both() all would be true
So based on the results above it looks like you want to use in() edges. However when we apply that to vertex 4 all the results would be false

jq how to merge array objects into single object

in jq its possible to add objects using the + operator
if you have an array
[
{
"a": "value"
},
{
"b": "value"
},
{
"c": "value"
}
]
I want to convert it into a single object { a:"value", b:"value", c:"value" }
I can use the following filter .[0] + .[1] + .[2], but i want to do it for the whole array without specifying all the indexes.
You can use reduce:
reduce .[] as $o ({}; . + $o)
returns:
{
"a": "value",
"b": "value",
"c": "value"
}
The simplest way is just to call add filter.
"The filter add takes as input an array, and produces as output the elements of the array added together. This might mean summed, concatenated or merged depending on the types of the elements of the input array - the rules are the same as those for the + operator (described above)."
Source: https://stedolan.github.io/jq/manual/#add
$ cat test.json
[
{
"a": "value"
},
{
"b": "value"
},
{
"c": "value"
}
]
$ jq 'add' test.json
{
"a": "value",
"b": "value",
"c": "value"
}
As mentioned by peak in the comment, you can even skip wrapping add filter with the quotes:
$ jq add test.json
{
"a": "value",
"b": "value",
"c": "value"
}
In case you want to merge all objects in array recursively (didn't find any similar answer here):
jq 'reduce .[] as $x ({}; . * $x)'

Resources