ArangoDb get edges with properties - arangodb

I am using ArangoDb newest version and I have problem.
I have two collections:
Country (and this is document collection) and Distance (this is edge collection with keys like: _from, _to, distance).
How can I get via AQL all information about countries where Country.Continent = 'Europe' with distances between them from edge collection?
SQL would be like this:
Select * from Country c, Distance d where c.Continent = 'Europe'
Thank You.

I have been working on a project recently and started using ArangoDB so hopefully I can be of assistance to you.
I took some inspiration for my answer from the below links of the Arango and AQL documentation:
AQL Graph Traversal
Shortest Path in AQL
Please see below my AQL query and do let me know if that helped at all. You can substitute the 'Europe' part on the FILTER for #Continent which will allow you to specify it dynamically, if need be.
FOR country IN Country
FILTER country.Continent == 'Europe'
FOR vertex, edge, path
IN OUTBOUND country Distance
RETURN path
This yields the following result for me. I just created some test collections with 2 edges linking countries together. I have included the vertex, edge as well as the path of the query in the 'FOR' part, so you are welcome to play around with the 'RETURN' part at the end by substituting the vertex or edge and seeing what results that yields for you.
[
{
"edges": [
{
"_key": "67168",
"_id": "Distance/67168",
"_from": "Country/67057",
"_to": "Country/67094",
"_rev": "_aecXk7---_",
"Distance": 5
}
],
"vertices": [
{
"_key": "67057",
"_id": "Country/67057",
"_rev": "_aecWJ0q--_",
"countryName": "UK",
"Continent": "Europe"
},
{
"_key": "67094",
"_id": "Country/67094",
"_rev": "_aecWZhi--_",
"countryName": "Italy",
"Continent": "Europe"
}
]
},
{
"edges": [
{
"_key": "67222",
"_id": "Distance/67222",
"_from": "Country/67057",
"_to": "Country/67113",
"_rev": "_aecYB9---_",
"Distance": 10
}
],
"vertices": [
{
"_key": "67057",
"_id": "Country/67057",
"_rev": "_aecWJ0q--_",
"countryName": "UK",
"Continent": "Europe"
},
{
"_key": "67113",
"_id": "Country/67113",
"_rev": "_aecWmEy--_",
"countryName": "Spain",
"Continent": "Europe"
}
]
}
]
For example if you substitute the 'RETURN path' part with 'RETURN edge', you will just retrieve the edges if that is all you need, as per below:
[
{
"_key": "67168",
"_id": "Distance/67168",
"_from": "Country/67057",
"_to": "Country/67094",
"_rev": "_aecXk7---_",
"Distance": 5
},
{
"_key": "67222",
"_id": "Distance/67222",
"_from": "Country/67057",
"_to": "Country/67113",
"_rev": "_aecYB9---_",
"Distance": 10
}
]

Related

Neo4J - How to query a graph and get the result as a tree with duplicates?

I`m working on a prototype of a community and have 4 nodes that are related as the image below.
sample data:
MERGE (a:User{key: 1})
MERGE (b:Tags{key: 2})
MERGE (c:Post{key: 3})
MERGE (d:Comment{key: 4})
MERGE (e:Comment{key: 5})
MERGE (f:Comment{key: 6})
MERGE (g:User{key: 7})
MERGE (h:User{key: 8})
MERGE (i:Post{key: 9})
MERGE (j:Tags{key: 10})
MERGE (k:Post{key: 11})
MERGE (l:Comment{key: 12})
MERGE (a)-[:CREATE]-(b)
MERGE (a)-[:CREATE]-(c)
MERGE (a)-[:REACT]-(c)
MERGE (a)-[:CREATE]-(d)
MERGE (a)-[:REACT]-(d)
MERGE (b)-[:RELATED]-(c)
MERGE (d)-[:REPLY]-(c)
MERGE (d)-[:REPLY]-(d)
MERGE (h)-[:REACT]-(c)
MERGE (g)-[:REACT]-(c)
MERGE (h)-[:CREATE]-(j)
MERGE (j)-[:RELATED]-(c)
MERGE (g)-[:CREATE]-(i)
MERGE (e)-[:REPLY]-(i)
MERGE (f)-[:REPLY]-(i)
MERGE (h)-[:CREATE]-(k)
MERGE (l)-[:REPLY]-(k)
MERGE (a)-[:REACT]-(l)
I want to retrieve all the activities for some user
This is my current query
MATCH reactions = (u:User{key:7})-[r]->(s)
WITH collect(reactions) as reactList
CALL apoc.convert.toTree(reactList, false)
YIELD value
RETURN value
The thing is that i want to retrieve the inner relations, so if an user REACT to a post i want to get the post and also get the user that created the post, and the tags that are related to that post.
My current response is
{
"CREATE": [
{
"_type": "Post",
"_id": 8,
"key": 9
}
],
"_type": "User",
"_id": 6,
"REACT": [
{
"_type": "Post",
"_id": 2,
"key": 3
}
],
"key": 7
}
Where i have the user properties spread on the object and a Key representing each relation containing the nodes.
I expect to have that kind of response but with the inner relations inside (1 level deep)
{
"REACT": [
{
"createdAt": "1649343307",
"REACT.createdAt": "1649358772",
"deletedAt": "1649425482",
"createdBy": "e7a6ca14-2bd7-4212-a445-7cfc0588593c",
"_type": "comment",
"commentBody": "undefined undefined asdasdasdasdasdasd",
"commentID": "1528ac92-0ff8-4fab-b86f-a61c50039373",
"_id": 308,
"deletedBy": "e7a6ca14-2bd7-4212-a445-7cfc0588593c",
"updatedAt": "1649343307",
"CREATE": [
{
"userFirstName": "someOthername",
"userLastName": "someOthername",
"userID": "e7a6ca14-2bd7-4212-a445-7cfc0588593c",
"_id": 32
}
]
},
{
"createdAt": "1648923859",
"topicKind": "text",
"topicID": "7ede6654-e462-4f7d-bdf7-10a54f4a3c4a",
"createdBy": "ac014441-7387-450c-ba4f-f94da233f169",
"updatedAt": "1648923859",
"topicBody": "Você são simplesmente uns merdas mesmo! Essa bosta desse programa de lixo!",
"topicTitle": "Preparing tests",
"RELATED": [
{
"identity": 1,
"labels": ["tag"],
"properties": {
"createdAt": "1648923848",
"tagID": "cd84cc95-7927-44ed-b2da-cf9e14044a39",
"createdBy": "ac014441-7387-450c-ba4f-f94da233f169",
"tagTitle": "Bull Market",
"updatedAt": "1648923848",
"tagDescription": "O melhor do mercado financeiro em uma única carteira de investimentos!"
}
}
],
"CREATE": [
{
"userFirstName": "someOthername",
"userLastName": "someOthername",
"userID": "ac014441-7387-450c-ba4f-f94da233f169",
"_id": 32
}
]
}
],
"CREATE": [
{
"createdAt": "1649201536",
"commentGuardDetails": "",
"createdBy": "c36dfac7-a003-4c17-a494-ac40d4b32b76",
"CREATE.createdAt": "1649201536",
"_type": "comment",
"commentBody": "acvadcdsh",
"commentID": "9c70af3a-35c2-4ab0-a9c6-33a518e7a103",
"_id": 191,
"commentGuard": "approved",
"updatedAt": "1649201536"
}
],
"userFirstname": "someName",
"userEmail": "someName#gmail.com",
"_id": 95,
"updatedAt": 1649378316
}
Thanks

How to perform a bidirectional upsert in ArangoDB

I'm working with a dataset similar to ArangoDB official "friendship" example, except I'm adding a "weight" concept on the Edge Collection. Like so :
People
[
{ "_id": "people/100", "_key": "100", "name": "John" },
{ "_id": "people/101", "_key": "101", "name": "Fred" },
{ "_id": "people/102", "_key": "102", "name": "Jacob" },
{ "_id": "people/103", "_key": "103", "name": "Ethan" }
]
Friendship
[
{ "_from": "people/100", "_to": "people/101", "weight": 27 },
{ "_from": "people/103", "_to": "people/102", "weight": 31 },
{ "_from": "people/102", "_to": "people/100", "weight": 12 },
{ "_from": "people/101", "_to": "people/103", "weight": 56 }
]
I want to write a function that, when someone interacts with someone else, UPSERTs the Friendship between the two (incrementing the weight by 1 if it existed before, or initializing with a weight of 1 if it's new).
The trouble is, when executing that function, I have now clue on which direction the friendship was initialized, thus I cannot really use an upsert. So 2 questions here :
Is there any way to make an upsert on an edge with "bidirectional" filter ?
Like so, but bidirectional
UPSERT {
// HERE, I BASICALLY WAN'T TO IGNORE THE SIDE
_from: ${people1}, _to: ${people2}
}
INSERT {
_from: ${people1}, _to: ${people2}, weight: 1
}
UPDATE {
weight: OLD.weight + 1
}
IN ${friendshipCollection}
RETURN NEW
Instead of trying to "select the friendship, no matter the direction"; should I rather actually duplicate the friendship on both directions (and constantly maintain / update it) ?

Traverse Arangodb graph with array filtering on edges

I have this test graph in arangodb
nodes:
[ { "_key": "A", "name": "A", "sector": "a"},
{ "_key": "B", "name": "B", "sector": "a"},
{ "_key": "C1", "name": "C1", "sector": "c"},
{ "_key": "C2", "name": "C2", "sector": "c"},
{ "_key": "C3", "name": "C3", "sector": "c"},
{ "_key": "C4", "name": "C4", "sector": "c"},
{ "_key": "D1", "name": "D1", "sector": "d"},
{ "_key": "D2", "name": "D2", "sector": "d"},
{ "_key": "E1", "name": "E1", "sector": "e"},
{ "_key": "E2", "name": "E2", "sector": "e"},
{ "_key": "E3", "name": "E3", "sector": "e"}]
edges:
[{ "_from": "V/A","_to": "V/D1", "cat": [{"c":1,"s":3}] },
{ "_from": "V/A","_to": "V/D2", "cat": [{"c":1,"s":1}] },
{ "_from": "V/B","_to": "V/D2", "cat": [{"c":2,"s":1}] },
{ "_from": "V/D1","_to": "V/E1", "cat": [{"c":1,"s":8}] },
{ "_from": "V/D1","_to": "V/E2", "cat": [{"c":1,"s":4}] },
{ "_from": "V/D2","_to": "V/E2", "cat": [{"c":1,"s":3},{"c":2,"s":4}] },
{ "_from": "V/D2","_to": "V/E3", "cat": [{"c":2,"s":4}] },
{ "_from": "V/C1","_to": "V/B", "cat": [{"c":2,"s":5}] },
{ "_from": "V/C1","_to": "V/A", "cat": [{"c":1,"s":6}] },
{ "_from": "V/C2","_to": "V/A", "cat": [{"c":1,"s":2}] },
{ "_from": "V/C3","_to": "V/A", "cat": [{"c":1,"s":1}] },
{ "_from": "V/C4","_to": "V/A", "cat": [{"c":1,"s":1}] },
{ "_from": "V/C4","_to": "V/B", "cat": [{"c":2,"s":2}] } ]
It is simplified part of much bigger graph (almost one thousand nodes, several thousand edges). Notice in this example that each edge has an property "cat" as an array of category objects. Actually, in the real set of data, each edge is part of one or more networks. There are 22 networks/categories. In this working example there are only two, 1 and 2. Each edge is part of one category, excepts D2->E3 being the only one here as member of both categories.
Problem: I have to traverse the graph by filtering/selecting edges of a chosen category(network in the real data) and its associated vertices, starting from a given vertex. Of course, avoiding loops and duplicated vertices or edges.
Example: starting from B and choosing category 2, I need to return this set:
v: [B,D2,E2,E3,C1,C4] and
e: [{B->D2, D2->E2, D2->E3, C1->B, C4->B]
In AQL I tried various filters starting from:
FOR v, e, p IN 0..3 any "nodes/D2" edges OPTIONS {bfs: true, uniqueVertices: 'global'}
//Here, the filter for cat 2 ?
return p
Nothing worked (sure, I am newbie in Arango).
Question 1: How to construct the filter ?
Question 2: How to format the results like in the example above? More exactly (the order of objects in each array doesn't matter):
[
nodes: [{name:"B",sector:"a"}, {name:"D2",sector:"d"}, {name:"E2",sector:"e"}, ...]
edges: [{source: "B", target: "D2", s:1}, {source: "D2", target: "E2", s:4}, ...]
]
Thanks for help.
1) In order to filter the entry "c":2 in cat, for all edges on the path (p.edges[*]) it has to be checked if the c attribute (.c) of the cat array (.cat[*]) includes the value [2].
Therefore we use the IN operator when accessing the sub-attribute array p.edges[*].cat[*].c.
FILTER [2] IN p.edges[*].cat[*].c
2) The return format can also be adjusted by accessing sub-attributes like:
return {'nodes':{'name':v.name,'sector':v.sector},'edges':{'source':e._from,'target':e._to, 's': e.cat[*].s}}
The adjusted query is:
FOR v, e, p IN 0..3 any "V/D2" edges
FILTER [2] IN p.edges[*].cat[*].c
return {'nodes':{'name':v.name,'sector':v.sector},'edges':{'source':e._from,'target':e._to, 's': e.cat[*].s}}

ArangoDB AQL Query - merge children into parent

I have a simple parent-child relationship in ArangoDB. Each parent document can have zero to many children. Let's say the parent document has attributes pa1, and the child docs have one attribute ca1, and a reference back to the parent _id of "_id_parent". How do I write an AQL query to return a result set like:
[{
"_key": "111",
"_id": "parent/111",
"pa1": "aaa",
"children": [{
"_key": "21",
"_id": "child/21",
"_id_parent": "parent/111",
"ca1": "www"
},
{
"_key": "22",
"_id": "child/22",
"_id_parent": "parent/111",
"ca1": "xxx"
}
]
},
{
"_key": "222",
"_id": "parent/222",
"pa1": "ddd",
"children": [{
"_key": "31",
"_id": "child/31",
"_id_parent": "parent/222",
"ca1": "yyy"
},
{
"_key": "32",
"_id": "child/32",
"_id_parent": "parent/222",
"ca1": "zzz"
}
]
}
]
In other words, how do I "flatten" this:
FOR p IN Parent
FILTER p.pa1 == #parm1
LET children = (
(FOR c IN Child
FILTER c._id_parent == p._id
RETURN c)
)
RETURN {p, children}
All what's left to do is to actually merge the children with the parent document:
RETURN MERGE(p, {children})
That is the short form of RETURN MERGE(p, {children: children}).
p is this:
{
"_id": "Parent/111",
"_key": "111",
"_rev": "_WLsUlK2--_",
"pa1": "aaa"
}
{children} or the more verbose {children: children} creates an object with a single attribute, with the name children and the value of the children variable:
{
"children": [
{
"_key": "21",
"_id": "Child/21",
"_rev": "_WLsW4Su--_",
"_id_parent": "Parent/111",
"ca1": "www"
},
{
"_key": "22",
"_id": "Child/22",
"_rev": "_WLsW8Zu--_",
"_id_parent": "Parent/111",
"ca1": "xxx"
}
]
}
MERGE() combines both objects. Since there is no overlap in attribute keys ("_id", "_key", "_rev", "pa1" vs. "children"), no top level attributes of p are replaced by children.
BTW: You can spare one pair of parentheses around the subquery expression
LET var = ( ( <subquery> ) ) - it is sufficient to do LET var = ( <subquery> ).

How to find duplicate values in mongodb using distinct query?

I am working on Mongodb distinct query, i have one collection with repeated entry, i am doing as per the created_at. But i want to fetch without repeated values.
Sample JSON
{
"posts": [{
"id": "580a2eb915a0161010c2a562",
"name": "\"Ah Me Joy\" Porter",
"created_at": "15-10-2016"
}, {
"id": "580a2eb915a0161010c2a562",
"name": "\"Ah Me Joy\" Porter",
"created_at": "25-10-2016"
}, {
"id": "580a2eb915a0161010c2a562",
"name": "\"Ah Me Joy\" Porter",
"created_at": "01-10-2016"
}, {
"id": "580a2eb915a0161010c2bf572",
"name": "Hello All",
"created_at": "05-10-2016"
}]
}
Mongodb Query
db.getCollection('posts').find({"id" : ObjectId("580a2eb915a0161010c2a562")})
So i want to know about distinct query of mongodb, please kindly go through my post and let me know.
try as follows:
db.getCollection('posts').distinct("id")
It will return all the unique IDs in the collection posts as follows:
["580a2eb915a0161010c2a562", "580a2eb915a0161010c2bf572"]
From MongoDB docs:
The example use the inventory collection that contains the following documents:
{ "_id": 1, "dept": "A", "item": { "sku": "111", "color": "red" }, "sizes": [ "S", "M" ] }
{ "_id": 2, "dept": "A", "item": { "sku": "111", "color": "blue" }, "sizes": [ "M", "L" ] }
{ "_id": 3, "dept": "B", "item": { "sku": "222", "color": "blue" }, "sizes": "S" }
{ "_id": 4, "dept": "A", "item": { "sku": "333", "color": "black" }, "sizes": [ "S" ] }
To Return Distinct Values for a Field (dept):
db.inventory.distinct( "dept" )
The method returns the following array of distinct dept values:
[ "A", "B" ]
Reference:
https://docs.mongodb.com/v3.2/reference/method/db.collection.distinct/
As per my understanding, you want to get distinct results which should eliminates the duplicate id in that collection
By using distinct in mongodb, It will return list of distinct values
db.getCollection('posts').distinct("id");
["580a2eb915a0161010c2a562", "580a2eb915a0161010c2bf572"]
So you should look into mongodb aggregation
db.posts.aggregate(
{ "$group" : { "_id" : "$id", "name" : {"$first" : "$name"}, "created_at" : {"$first" : "$created_at"} }}
)
The output will be list of results which eliminates the duplicate id documents

Resources