How do I return information in a path in a multi-hop query? - nebula-graph

The example statement is as follows:
match (v1:player) -[:follow]->(v2:player)-[:serve]->(t:team) where v1.name == "tom" return v1.name, v2.name, t.name;
When the edge serve does not exist in v2, the whole statement does not return any data.
Can you tell me how to return v1.name, v2.name even if the serve edge of v2 does not exist?

To return v1.name and v2.name even if the serve edge of v2 does not exist, you can use an optional match clause in your NebulaGraph query.
For example:
match (v1:player) -[:follow]->(v2:player) /
optional match (v2)-[e:serve]->(t:team) /
where v1.name == "tom" /
return v1.name, v2.name, t.name;

Related

Azure Cosmos DB (NOT IS_DEFINED OR ) clause with JOIN always evaluates to false

I have a document:
{
contact: {
id: '123'
},
channels: [
{
... some channel info...
}
],
lastUpdatedEpoch: 1583937675
}
And I have following query which doesn't return the above document:
SELECT p FROM p JOIN c IN p.channels
WHERE (NOT IS_DEFINED(p.lastUpdatedEpoch) OR p.lastUpdatedEpoch < 1585733881)
AND p.contact.id = '123'
But when I remove NOT IS_DEFINED check, it correctly returns the document:
SELECT p FROM p JOIN c IN p.channels
WHERE (p.lastUpdatedEpoch < 1585733881)
AND p.contact.id = '123'
I also tried replacing NOT IS_DEFINED clause with FALSE and it returns the document:
SELECT p FROM p JOIN c IN p.channels
WHERE (FALSE OR p.lastUpdatedEpoch < 1585733881)
AND p.contact.id = '123'
Also, if I remove JOIN, the query works as expected and returns the document:
SELECT p FROM
WHERE (NOT IS_DEFINED(p.lastUpdatedEpoch) OR p.lastUpdatedEpoch < 1585733881)
AND p.contact.id = '123'
To me this behavior is unexpected. When lastUpdatedEpoch is defined, I expect the same result from the first and second query (aside from the fact NOT_ISDEFINED will cause the index to be not used).
Could someone please explain what's going on here?
I try to reproduce your issue on my side but failed.The result is expected for me.
Test sample data:
Sql Output:
It seems that you did not refer any columns in channels.I suggest you create some simple test data to verify whether your sql is right.Then try to compare with your actual data.
I contacted CosmosDB team, and the team was able give some insight about the issue.
There was new optimization that was recently put in to allow inequality and NotIsDefined expressions to utilize the index. There was some issue with this optimization, and the team disabled this feature for now. If you are able to observe this issue with your cluster, please contact their support team.

Xquery variable concat based on condition

I am trying to concat the value of an element based on certain condition, but unable to do so. What's wrong here?
For below given sample structure, I need to concat the value of CID based upon OutcomeCode code. Say if we have OutcomeCode as OC and PC, then we should display concatenated value of CId in a string variable.
<v4:ValidateResponse xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v4="http://service.com/v4">
<v4:Details>
<v4:Detail>
<v4:CId>001</v4:CId>
</v4:Detail>
<v4:OutcomeCode>FC</v4:OutcomeCode>
</v4:Details>
<v4:Details>
<v4:Detail>
<v4:CId>002</v4:CId>
</v4:Detail>
<v4:OutcomeCode>PC</v4:OutcomeCode>
</v4:Details>
<v4:Details>
<v4:Detail>
<v4:CId>003</v4:CId>
</v4:Detail>
<v4:OutcomeCode>OC</v4:OutcomeCode>
</v4:Details>
</v4:ValidateResponse>
Here is my transformation
as xs:string
{
for $Details in $ValidateResponse /*:Details
let $OutcomeCode := data($Details/*:OutcomeCode)
return
if (($OutcomeCode ='OC') or ($OutcomeCode='PC'))
then
contact('CID is-',data($Details/*:Detail/*:CId))
else
fn:data('Technical_Check')
};
I am unable to get concat values.
Expected result should be like: CID is- 002,003
as these 2 meet the OC and PC condition.
You could simplify this for loop and combine the criteria into a single XPath to select the CId from Details that have OutcomeCode of "OC" or "PC".
Then, use string-join() in order to produce a comma separated value.
Then, use concat() to produce a string with the prefix and the CSV value:
concat('CID is- ',
string-join(
$ValidateResponse/*:Details[*:OutcomeCode =('OC','PC')]/*:Detail/*:CId,
",")
)

Using the replace function in firestore security rules

I'm struggling with Firestore security rules. I want to check on a value that needs the replace function, i.e. an e-mail address. I can find some documentation in the general security docs, but that does not seem to work with Firestore.
For example this works:
allow write: if resource.data.members.data[(request.auth.token.email)] in ["admin"];
but this doesn't (and I changed the key in the members object accordingly):
allow write: if resource.data.members.data[(request.auth.token.email.replace('.' , ',')] in ["admin"];
Another option would be to have a way to use dots in the address of a query, so they don't have to be replaced like this:
var emailSanitized = email.replace('.' , '.');
db.collection('someCollection').where('members.' + emailSanitized, '==', 'admin')
Any ideas here?
A little late, but you can simulate the replace function on a string with this one :
function replace(string, replace, by) {
return string.split(replace).join(by);
}
So you need to define this function in your firestore.rules file and then you can call replace(request.auth.token.email, '.' , ',') to get the same result as request.auth.token.email.replace('.' , ',') in javascript.
There are two reasons why you might have been having issues.
The replace function was added to Security Rules after you asked your question.
The replace function uses regular expressions for the first argument and so matching on '.' will match literally everything.
Consider instead using: request.auth.token.email.replace('\\.' , ',')
var emailSanitized = email.replace('.' , '.');
db.collection('someCollection').where('members.' + emailSanitized, '==', 'admin')

Invalid UpdateExpression when using parameter from ValueMap as index (REMOVE myArray[:index])

I try to remove an element from an array. This operation
UpdateItemSpec updateItemSpec = new UpdateItemSpec()
.withPrimaryKey("id", id)
.withNameMap(new NameMap().with("#P", "myArray"))
.withValueMap(new ValueMap().withInt(":index", index))
.withUpdateExpression("REMOVE #P[:index]");
table.updateItem(updateItemSpec);
results with com.amazonaws.services.dynamodbv2.model.AmazonDynamoDBException: Invalid UpdateExpression: Syntax error; token: ":index", near: "[:index]"
If I remove ValueMap and concat string like this "REMOVE #P["+index+"]" it works fine but this solution looks ugly (like old bad SQL injection stuff). Is there a way to provide an index as a parameter?
REMOVE - Removes one or more attributes from an item
REMOVE - The UpdateExpression is expected to have attribute name only for REMOVE. It should not contain attribute value similar to SET.
There is no alternative other than String concatenation by some means.

Remove paths which are subsets of a longer path

I would like to obtain the longest path that are connected to a single parent via Neo4J Cypher query.
My current queries are like this:
MATCH p=(N1:Node)-[REL*..2]->(N2:Node) WHERE N2.RIC =~"some ticker.*" RETURN p limit 50
However, i am getting results like this
a->b->parent
b-> parent
In my own opinion , i would like to keep only the longest path.
Also, is there anyway to return the direction of the query ? IE: i can see the from/to of a relationship in the output of the query.
Thanking in advance !
If you want just the longest path then you can do:
MATCH path=(N1:Node)-[REL*..2]->(N2:Node)
WHERE N2.RIC =~"some ticker.*"
RETURN p
ORDER BY length(p) DESC
LIMIT 1
As for getting the directions, this depends on the driver that you use. In the Neo4j HTTP transaction endpoint if you specify REST for resultDataContents, it will return a directions for any path objects that you return. Here is how you set that:
http://neo4j.com/docs/stable/rest-api-transactional.html#rest-api-execute-statements-in-an-open-transaction-in-rest-format-for-the-return
Here is an example of what that looks like:
"rest": [
{
"relationships": [
"http://localhost:7474/db/data/relationship/587"
],
"nodes": [
"http://localhost:7474/db/data/node/1002",
"http://localhost:7474/db/data/node/1001"
],
"directions": [
"<-"
],
"length": 1,
"start": "http://localhost:7474/db/data/node/1002",
"end": "http://localhost:7474/db/data/node/1001"
}
]
EDIT:
Responding to your comment, in order to get the longest path for each parent:
MATCH path=(N1:Node)-[REL*..2]->(N2:Node)
WHERE N2.RIC =~"some ticker.*"
WITH N1, N2, collect(p) AS paths
ORDER BY length(p) DESC
RETURN N1, N2, paths[0] AS longest_path
I wasn't sure which side is supposed to be the parent, so I returned both N1 and N2 which should give you the longest path for each combination of those two. You can remove either one to get the longest path leading to/from the node which is left.

Resources