I want to get nested objects in the form of
{ country :
{code:'IN',states:
{code:'TG',cities:
{code:'HYD',malls:
{[shopping-mall1],[shopping-mall2],.....}
},
{code:'PKL',malls:
{[shopping-mall1],[shopping-mall2],.....}
}
},
{code:'AP',cities:
{code:'VJY',malls:
{[shopping-mall1],[shopping-mall2],.....}
}
}
}
}
MY graph is in format
vertex: country ---> states ---->cities ---> mallls
edges: (type:'state') ('type','city')
ex: inE('typeOf').outV().has('type','state') move to next vertex "states".
next same inE('typeOf').outV().has('type','city') moves to "city" vertex. then "malls" vertex .
And tired to write the code, some vertex has no cities i have an error that situavation."
error
The provided traverser does not map to a value: v[8320]->[JanusGraphVertexStep(IN,[partOf],vertex), HasStep([type.eq(city)]), JanusGraphPropertiesStep([code],value)]
Thats why i am using coalesce because some state has not an edge 'inE('partOf').outV().has('type','city')' means no city
.by(coalesce(select('states').inE('partOf').outV().has('type','city'))
My query
g.V().hasLabel('Country').has('code','IN')
.project('country')
.by(project('code','states')
.by(values('code'))
.by(inE('partOf').outV().has('type','state').has('code').as('states').
project('code','cities')
.by(select('states').values('code'))
.by(coalesce(select('states').inE('partOf').outV().
has('type','city').has('code').as('cities').
project('code','malls')
.by(select('cities').values('code'))
.by(coalesce(select('cities').inE('partOf').outV().
has('type','malls').valueMap(),constant(0))),
constant(0)))))
But the result is
{country={code=IN, states={code=DD, cities=0}}}
here i am getting one state 'DD' and that state is no city,so it gives 'cities = 0".
the above result is only one state is coming, i want all states, cities and malls in each city.
Please update query or change query
In order to collect all the results you should use .fold() traversal which returns a list of the collected traversals. without fold you will get only the first traversal like in your example.
In order to keep the types the same I changed the constant to [] instead of 0.
It was also not clear if the "type" property is on the edge or the vertex. I find it more appropriate to have it on the edge, so I fixed it as well by moving the has('type',...) between the inE() and outV().
Last, you don't need to "store" the traversal using "as" and then "select" it.
This query should give you the required result:
g.V().hasLabel('Country').has('code','IN')
.project('country')
.by(project('code','states')
.by(values('code'))
.by(inE('partOf').has('type','state').outV().has('code')
.project('code','cities')
.by(values('code'))
.by(coalesce(inE('partOf').has('type','city').outV().has('code')
.project('code','malls')
.by(values('code'))
.by(coalesce(
inE('partOf').has('type','malls').outV().valueMap(),
constant([])).fold()),
constant([])).fold())
.fold()))
Related
For my data model, I have the following:
type defines an item
The project owns an item
Type is connected to anchors (Suppose the anchor is country)
Item is connected to a particular anchor instance (anchor instance
will have corresponding value for anchor, suppose US)
I am trying to read an item along with the type, anchorNames and anchorValues.
Following is the query I have written:
g.V().hasLabel('Type').as('t')
.outE('DEFINES').inV().hasLabel('Item').has('dataId',’test-id').has('version','1').as('i')
.inE('OWNS').outV().hasLabel('Project').select('i')
.project('i','t','anchorNames','anchorValues')
.by(__.valueMap(true))
.by(__.in().hasLabel('Type').valueMap(true))
.by(out().in().hasLabel('Anchor').values('name').fold())
.by(out().as('AnchorInstance').select('AnchorInstance')
.by(values('value','secondaryValue').fold()).fold())
I get i and t but the result for anchorNames and anchorValues is as follows:
{anchorNames=[status, status, country], anchorValues=[[OK], [US], [FAIL]]}
However I am expecting the following:
{anchorNames=[status, status, country], anchorValues=[[OK], [FAIL], [US]]}
I need the ordering between the anchorNames and anchorValues as shown above.
I think the best approach will be to get the name and the corresponding values together.
g.V().hasLabel('Type').as('t')
.out('DEFINES').hasLabel('Item').has('dataId',’test-id').has('version','1').as('i')
.in('OWNS').hasLabel('Project').select('i')
.project('i','t','anchors')
.by(__.valueMap(true))
.by(__.in().hasLabel('Type').valueMap(true))
.by(out().project('anchorNames','anchorValues')
.by(__.in().hasLabel('Anchor').values('name'))
.by(values('value','secondaryValue').fold()).fold())
I'm having trouble constructing the gremlin query to give me all of the Edge details(label, properties) and also the ID's of the Inv and OutV adjoining Vertex's (I don't need any more info from the linked Vertex's, just the ID's).
All I have is the Edge ID as a starting point.
So my Edge is as follows:
Label: "CONTAINS"
id: c6b4f3cb-f96e-cc97-dedb-e405771cb4f2
keys:
key="ekey1", value="e1"
key="ekey2", value="e2"
inV has id 50b4f3cb-f907-c31c-6284-1a3463fd72b9
outV has id 7cb4f3cb-d9a2-1398-61d7-9339be34833b
What I want is a single query that will return me something like -
"CONTAINS", "c6b4f3cb-f96e-cc97-dedb-e405771cb4f2", {ekey1=e1, ekey2=e2, ...}, "50b4f3cb-f907-c31c-6284-1a3463fd72b9", "7cb4f3cb-d9a2-1398-61d7-9339be34833b"
I can get the info in separate queries i.e.
g.E("c6b4f3cb-f96e-cc97-dedb-e405771cb4f2").bothV()
==>v[50b4f3cb-f907-c31c-6284-1a3463fd72b9]
==>v[7cb4f3cb-d9a2-1398-61d7-9339be34833b]
g.E("c6b4f3cb-f96e-cc97-dedb-e405771cb4f2").valueMap()
==>{ekey1=e1, ekey2=e2}
g.E("c6b4f3cb-f96e-cc97-dedb-e405771cb4f2").label()
==>CONTAINS
But I can't for the life of me work out how to combine these into one.
You could use project() to get what you're looking for:
g.E("c6b4f3cb-f96e-cc97-dedb-e405771cb4f2").
project('ekey1', 'inV', 'outV', 'label').
by('ekey1').
by(inV().id()).
by(outV().id()).
by(label).
I'm trying to copy a vertex node and retain it's relationships in ArangoDB. I'm getting a "access after data-modification" error (1579). It doesn't like it when I iterate over the source node's edges and insert an edge copy within the loop. This makes sense but I'm struggling to figure out how to do what I'm wanting within a single transaction.
var query = arangojs.aqlQuery`
let tmpNode = (FOR v IN vertices FILTER v._id == ${nodeId} RETURN v)[0]
let nodeCopy = UNSET(tmpNode, '_id', '_key', '_rev')
let nodeCopyId = (INSERT nodeCopy IN 'vertices' RETURN NEW._id)[0]
FOR e IN GRAPH_EDGES('g', ${nodeId}, {'includeData': true, 'maxDepth': 1})
let tmpEdge = UNSET(e, '_id', '_key', '_rev')
let edgeCopy = MERGE(tmpEdge, {'_from': nodeCopyId})
INSERT edgeCopy IN 'edges'
`;
This quesion is somewhat similar to 'In AQL how to re-parent a vertex' - so let me explain this in a similar way.
One should use the ArangoDB 2.8 pattern matching traversals to solve this.
We will copy Alice to become Sally with similar relations:
let alice=DOCUMENT("persons/alice")
let newSally=UNSET(MERGE(alice, {_key: "sally", name: "Sally"}), '_id')
let r=(for v,e in 1..1 ANY alice GRAPH "knows_graph"
LET me = UNSET(e, "_id", "_key", "_rev")
LET newEdge = (me._to == "persons/alice") ?
MERGE(me, {_to: "persons/sally"}) :
MERGE(me, {_from: "persons/sally"})
INSERT newEdge IN knows RETURN newEdge)
INSERT newSally IN persons RETURN newSally
We therefore first load Alice. We UNSET the properties ArangoDB should set on its own. We change the properties that have to be uniq to be uniq for Alice so we have a Sally afterwards.
Then we open a subquery to traverse ANY first level relations of Alice. In this subequery we want to copy the edges - e. We need to UNSET once more the document attributes that have to be autogenerated by ArangoDB. We need to find out which side of _from and _to pointed to Alice and relocate it to Sally.
The final insert of Sally has to be outside of the subquery, else this statement will attempt to insert one Sally per edge we traverse. We can't insert Saly in front of the query as you already found out - no subsequent fetches are allowed after the insert.
I'm using GRAPH_TRAVERSAL to get the path from a list of nodes to the head of the tree. This works perfectly except when the example happens to be the head of the tree. In this case, the edgeCollection doesn't have an inbound entry for this object so it doesn't appear in the results.
FOR v IN GRAPH_TRAVERSAL('gdp2',
[{_id:'pmsite/14419285155'}],
'inbound',{edgeCollection:'child'})
RETURN v
The result is an empty list: []
Is there a way I can guarantee that the starting node is on the list? It would be a pain to go through the list of examples to segregate which ones are at the head of a tree.
The problem is within the query itself. It contains a subtle error which is hard to spot:
[{_id:pmsite/14419285155}],
This is missing the quotes around pmsite/14419285155.
What this query realy does is to devide (probably the count of) the collection pmsite by the id 14419285155 and put in this as {_id: divcount}.
If you add the missing quotes, the query should do exactly what you want there. (edit: quotes were present in the original query, fixed the post.)
hint: db._explain() gives information about that.
Trying to reproduce, using the knows sample graph:
arangosh> var examples = require("org/arangodb/graph-examples/example-graph.js");
arangosh> var g = examples.loadGraph("knows_graph");
arangosh> db._query("FOR e IN GRAPH_TRAVERSAL('knows_graph', [{_id: 'persons/eve'}], 'inbound', {edgeCollection: 'knows'}) return e").toArray()
[
[
{
"vertex" : {
"_id" : "persons/eve",
"_rev" : "1405497100114",
"_key" : "eve",
"name" : "Eve"
}
}
]
]
However what creates a somewhat similar behaviour is to use a collection not part of the graph definition:
arangosh> db._create("othercol")
arangosh> db.othercol.save({_key: "1" })
arangosh> db._query("FOR e IN GRAPH_TRAVERSAL('knows_graph', [{_id: 'othercol/1'}], 'inbound', {edgeCollection: 'knows'}) return e").toArray()
[ ]
As pointed out in the Comments, edge relations have a direction. If you want to have edges pointing in both directions, you need to create a second relation in the other direction. Edges not fullfilling the edge definitions may be ignored.
I am new to graph databases and OrientDB, so I appreciate your patience.
I have the following SQL query to produce an expanded set of results for the shortest path between two vertices (I am using the GratefulDeadConcerts database):
select expand(sp) from (select shortestPath(#9:2,#9:15,'BOTH') as sp)
For whatever reason, using expand without aliasing produces no results, but that isn't really an issue.
What I want is not the shortest path, but a collection of potential paths and branches.
I have tried playing with travesedVertex:
SELECT traversedVertex(-1) FROM ( TRAVERSE out() FROM #9:2 WHILE $depth <= 10 )
But I don't know how to set the destination, or (honestly) how to interpret the results I get.
EDIT
If there are multiple ways to get from A to B, I want each of those paths returned as a set, something like:
{
paths: [
[#9:2, #4:16, #8:7, #9:15],
[#9:2, #4:2, #16:5, #11:3, #9:15],
[#9:2, #4:4, #11:6, #9:15]
]
}
Thank you for your help.
First, $path is the string representation of the current path.
Second, you can filter on the destination columns on the where clause of the outer query. Try this :
SELECT
$path
FROM
( TRAVERSE
out()
FROM
#9:2
WHILE
$depth <= 10 )
WHERE
#rid = #9:15
I get the following output :
Is this what you are looking for ?
If I don't add the where clause, I get this output :