Create a empty array inside a Gremlin traversal? - gremlin

This sounds silly but is there a way to create a empty array inside a Gremlin traversal?
For the query below:
g.V().has('person','name', 'marko').project('a', 'b').by().by()
I want to project b as an empty array. I have tried:
g.V().has('person','name', 'marko').project('a', 'b').by().by(constant("").fold())
But constant("").fold() is not actually empty constant("").fold().count() returns 1. This applies to constant(null).fold() as well.

Is this what you are looking for
g.withSideEffect('x',[]).V().has('person','name','marko').project('a','b').by(select('x')).by('name')
==>[a:[],b:marko]

An empty array/collection would actually be a fold() of nothing. You'll get nothing if you filter everything, hence:
g.V().has('person','name','marko').
project('a', 'b').
by().
by(__.not(identity()).fold())

Related

Custom sorting issue in MarkLogic?

xquery version "1.0-ml";
declare function local:sortit(){
for $i in ('a','e','f','b','d','c')
order by $i
return
element Result{
element N{1},
element File{$i}
}
};
local:sortit()
the above code is sample, I need the data in this format. This sorting function is used multiple places, and I need only element N data some places and only File element data at other places.
But the moment I use the local:sortit()//File. It removes the sorting order and gives the random output. Please let me know what is the best way to do this or how to handle it.
All these data in File element is calculated and comes from multiple files, after doing all the joins and calculation, it will be formed as XML with many elements in it. So sorting using index and all is not possible here. Only order by clause can be used.
XPath expressions are always returned in document order.
You lose the sorting when you apply an XPath to the sequence returned from that function call.
If you want to select only the File in sorted order, try using the simple mapping operator !, and then plucking the F element from the item as you are mapping each item in the sequence:
local:sortit() ! File
Or, if you like typing, you can use a FLWOR to iterate over the sequence and return the File:
for $result in local:sortit()
return $result/File

find all edges for a result set of nodes

I have a query that returns a set of nodes, like this:
g.V().as("a","node").has("prop1", true).out().as("b","node").hasLabel("device")
.in().as("c","node").hasLabel("lbl1").has("prop1", false).select("a","b","c").limit(200)
Now I want to return all these nodes and any edge between them as my result. I tried the following but it always comes back empty:
g.V().(....)
.select("a","b","c").limit(200)
.select("node").dedup().fold().as('all')
.unfold().as('start').bothE().as('edge').otherV().as('end')
.where(within('all'))
.select('start', 'edge', 'end').dedup()
unfortunately this always comes back empty. I think my where filter is incorrect. How do I filter the result for only those where node "c" is one of those in "a"?
I want to keep this generic so I can use it to process multiple different queries that all return a set of nodes.
For this query, you should check that out vertex is in the set of the beginning vertex. So you should first fold() the start set and then check against it with within() predicate inside where
Here is query for example g = TinkerFactory.createModern().traversal()
g.V().limit(3).fold().as('all').
unfold().as('a').outE().as('b').otherV().as('c').
where(within('all')).
select('a', 'b', 'c')
See 2nd example here: https://tinkerpop.apache.org/docs/current/reference/#where-step

How do you return a single object as opposed to a single item in an array?

From a traverser, if I just want the first item in the list of vertexes, how would I go about returning it as an object?
I've tried:
g.V()
.has("Project", "id", eq("someid"))
.outE("Contains")
.inV()
.hasLabel("Goal")
.sample(1)
.values("name")
Also tried:
g.V()
.has("Project", "id", eq("someid"))
.outE("Contains")
.inV()
.hasLabel("Goal")
.limit(1)
.values("name")
I've also tried fold but none of them worked for me. Any ideas?
I'm not quite following what you want but your either traversal should only return one "name" value and not a list of "name" values, though I think I'd prefer the second since you said you want the first item returned. I'd re-write it as follows though:
g.V().has("Project", "id", "someid").
out("Contains").hasLabel("Goal").
values("name")
limit(1)
You just pasted some Gremlin here, but you can also next() the Iterator to get that single first object:
String name = g.V().has("Project", "id", "someid").
...
limit(1).next()
If you're seeing some other behavior for some reason in the return values please update your question to include a sample data script (example) so that it's easy to reproduce in the Gremlin Console.

Xquery Where clause not working when using nested query

Good Day,
I'm new to xquery.
I'm trying to execute xquery with a where clause that returns the values greater than a value returned from a nested query as show below. It runs but returns values that are not greater than the returned value
If I use the where clause directly with the value it works fine. I'm using BaseX to execute my query. Appreciate any feedback, I believe the parser may be reading my subquery wrong.
for $y in doc("url.xml")/taxi_stations/stand
where $y/taxis>=
(
for $x in doc("url.xml")/taxi_stations/stand
where $x/name="Jacksonville"
return data($x/taxis)
)
return ($y/taxis,$y/name)
What is the value of $taxis? It's possible your comparisons are happening on strings, not numbers.
In your nested return, you call data() on $x/taxis - assuming that correctly returns a number value, then $y/taxis in your outer where clause should probably also be wrapped in data().
However, if there is no schema on your document, then data() will simply return a string. In that case you should convert your taxis element to a number using fn:number() or directly casting it like $y/taxis/xs:integer(.).

An XDMP-NOTANODE error using xquery in marklogic

I'm getting the XDMP-NOTANODE error when I try to run an XQuery in MarkLogic. When I loaded my xml documents I loaded meta data files with them. I'm a student and I don't have experience in XQuery.
error:
[1.0-ml] XDMP-NOTANODE: (err:XPTY0019) $article/article/front/article-meta/title-group/article-title -- xs:untypedAtomic("
") is not a node
Stack Trace
At line 3 column 77:
In xdmp:eval("(for $article in fn:distinct-values(/article/text()) &#1...", (), <options xmlns="xdmp:eval"><database>4206169969988859108</database> <root>C:\mls-projects\pu...</options>)
$article := xs:untypedAtomic("
")
1. (for $article in fn:distinct-values(/article/text())
2.
3. return (fn:distinct-values($article/article/front/article-meta/title-group/article-title)
4.
5.
Code:
(
for $article in fn:distinct-values(/article/text())
return (
fn:distinct-values($article/article/front/article-meta/title-group/article-title/text())
)
)
Every $article is bound to an atomic value (fn:distinct-values() returns a sequence of atomic values). Then you try to apply a path expression (using the / operator) on $article. Which is forbidden, as the path operator requires its LHS operator to be nodes.
I am afraid your code does not make sense enough for me to suggest you an actual solution. I can only pinpoint where the error is.
Furthermore, using text() at the end of a path is most of the time a bad idea. And if /article is a complex document, it is certainly not what you want. One of the text nodes you select (most likely the first one) is simply one single newline character.
What do you want to achieve?
Your $article variable is bound to an atomic value, not a node() from the article document. You can only use an XPath axis on a node.
When you apply the function distinct-values() in the for statement, it returns simple string values, not the article document or nodes from it.
You can probably make things work by using the values in a predicate filter like this:
for $article-text in fn:distinct-values(/article/text())
return
fn:distinct-values(/article[text()=$article-text]/front/article-meta/title-group/article-title/text())
Note: The above XQuery should avoid the XDMP-NOTANODE error, but there are likely easier (and more efficient) solutions for achieving your goal. If you were to post a sample of your document and describe what you are trying to achieve, we could suggest alternatives.
Bit of a wild guess, but you have two distinct-values in your code. That makes me think you want a unique list of articles, and then finally a unique list of article-title's. I would hope you already have unique articles in your database, unless you are explicitly attempting to de-duplicate them.
In case you just want the overall unique list of article titles, I would do something like:
distinct-values(
for $article in collection()/article
return
$article/front/article-meta/title-group/article-title
)
HTH!

Resources