NEO4J MERGE is not working as expected - database

I am new in neo4j and I am having problems with the MERGE clause. I have a method to do queries like this:
def upsert (idValue, valueField1):
query = "MERGE (n:Node {id: '" + idValue+ "'}) "
query += "ON MATCH SET n.field1= n.field1+ " + str(valueField1) + " "
query += "ON CREATE SET n = {id: '" + idValue + "', field1: 0} "
return db.run(query)
Then, I am calling the method like this:
upsert("1", 0)
upsert("2", 0)
upsert("3", 5)
upsert("1", 2)
upsert("1", 1)
So, afterthat, I expected this:
node (id="1", field1=3)
node (id="2", field1=0)
node (id="3", field1=0)
But, I am getting this:
node (id="1", field1=2)
node (id="2", field1=0)
node (id="3", field1=0)
In addition, If I do the same calls again, I got this:
node (id="1", field1=4)
node (id="2", field1=0)
node (id="3", field1=5)
Could anyone explain me what is happening and what am I doing wrong please? I was looking for on internet, but I couldn't find anything helpful for me.

With this query, that is exactly the same as what you are doing, I have the good result :
WITH [
{idValue:'1', valueField1:0},
{idValue:'2', valueField1:0},
{idValue:'3', valueField1:5},
{idValue:'1', valueField1:2},
{idValue:'1', valueField1:1}
] AS data
UNWIND data AS item
MERGE (n:Node {id:item.idValue})
ON MATCH SET n.field1= n.field1 + item.valueField1
ON CREATE SET n = {id:item.idValue, field1: 0}
And then with MATCH (n:Node) RETURN n.id, n.field1 ORDER BY n.id LIMIT 25 :
n.id n.field1
"1" 3
"2" 0
"3" 0
So I don't think that the problem comes from the query itself, but from its construction.
You should consider to use a parameterized query. It will be easier to read the query, but also code it and it's more performant in Neo4j.
So your code should be :
def upsert (idValue, valueField1):
query = "MERGE (n:Node {id:$id}) "
" ON MATCH SET n.field1= n.field1 + $value"
" ON CREATE SET n = {id:$id, field1: 0}"
return db.run(query, id=idValue, value=valueField1)

Related

How to simplify neo4j query with multiple CASE's

We use the following cypher query in our project (just the relevant part, there's a bunch of MATCH and WHERE before this):
"RETURN entry.id AS id,\n" +
...
" CASE WHEN ljCase1 IS NOT NULL THEN {id: ljCase1.id, guide: false} \n" +
" ELSE CASE WHEN ljCase2 IS NOT NULL THEN {id: ljCase2.id, guide: true}\n" +
" ELSE CASE WHEN ljCase3 IS NOT NULL THEN {id: ljCase3.id, guide: true} END\n" +
" END\n" +
" END AS learningJourney\n" +
...
It works properly but I feel like this isn't done as clean as it could be.
Is there a way to simplify this part of the query?
perhaps something along the line of this, using COALESCE to avoid the nested CASE
WITH COALESCE(ljCase1,ljCase2,ljCase3) AS myCase
WITH CASE myCase
WHEN x THEN ..
WHEN y THEN ..
ELSE ..
END

Nested match_recognize query not supported in flink SQL?

I am using flink 1.11 and trying nested query where match_recognize is inside, as shown below :
select * from events where id = (SELECT * FROM events MATCH_RECOGNIZE (PARTITION BY org_id ORDER BY proctime MEASURES A.id AS startId ONE ROW PER MATCH PATTERN (A C* B) DEFINE A AS A.tag = 'tag1', C AS C.tag <> 'tag2', B AS B.tag = 'tag2'));
And I am getting an error as : org.apache.calcite.sql.validate.SqlValidatorException: Table 'A' not found
Is this not supported ? If not what's the alternative ?
I was able to get something working by doing this:
Table events = tableEnv.fromDataStream(input,
$("sensorId"),
$("ts").rowtime(),
$("kwh"));
tableEnv.createTemporaryView("events", events);
Table matches = tableEnv.sqlQuery(
"SELECT id " +
"FROM events " +
"MATCH_RECOGNIZE ( " +
"PARTITION BY sensorId " +
"ORDER BY ts " +
"MEASURES " +
"this_step.sensorId AS id " +
"AFTER MATCH SKIP TO NEXT ROW " +
"PATTERN (this_step next_step) " +
"DEFINE " +
"this_step AS TRUE, " +
"next_step AS TRUE " +
")"
);
tableEnv.createTemporaryView("mmm", matches);
Table results = tableEnv.sqlQuery(
"SELECT * FROM events WHERE events.sensorId IN (select * from mmm)");
tableEnv
.toAppendStream(results, Row.class)
.print();
For some reason, I couldn't get it to work without defining a view. I kept getting Calcite errors.
I guess you are trying to avoid enumerating all of the columns from A in the MEASURES clause of the MATCH_RECOGNIZE. You may want to compare the resulting execution plans to see if there's any significant difference.

Multiple tag search engine

Whenever we use hashtag for searching that always results from a single tag (except Tumblr).
Just wondering is there a search engine allows multiple tag search?
I suppose that using different combination of tags could be fun and accurate:
#A general results
#A, #B more specific
#A, #B, #C, #D close to the truth what attributes (tags) are given.
Is any website served in this way?
Or how can I build a database to make this happened?
Thank you a lot.
This is old and written in VB but the principle I think will work for you.
This code is not completely limiting to Images that have all of the tags it is instead pushing the images with the most tag hits to the top.
This code works from the idea of show the user what fits best first but then give them other options below. Where as your AND scenario would cut out something that worked for 4 out of 5 of the tags. In this scenario they would just show below tags that had 5 out of 5.
So if you had some images with tags like:
Given:
Image1 woman,dog,panda
Image2 woman,telephone,smiling
Image3 man,dog,panda,banana
Image4 man,telephone,smiling
Yield:
A tag search of "telephone smiling" would score [Image2] and [Image4] to the top of the listing.
A tag search of "panda" would only yield Image1 and Image3.
A tag search of "man dog panda banana" Would yield Image3 as the top followed by Image1 followed by Image4.
This implementation is for finding the best image based on tags.
You create 3 tables in your SQL database as such (if you are doing webpages or stories or whatever change image to that for your own clarity):
SQL Tables:
imageTag [INT ID, String Tag]
imageImages [INT ID, NVARCHAR(2000) Path]
imageConnections [INT TagID, INT ImageID]
VB.NET Code:
'The beef of the SQL statement to get the scored results is here.
Dim SearchString As String =
"SELECT it.path, count(it.path) AS cnt, it.Id, it.name, it.description, it.updated FROM imageimages AS it, imageconnections AS itt, imagetags AS t WHERE " + _
"{REPLACE-TAG} AND t.id = itt.tagid AND it.id = itt.imageid " + _
"GROUP BY Path, it.ID, it.name, it.description, it.updated ORDER BY cnt DESC"
Dim keywords As String() = tstSearch.Text.Split(New String() {" "}, StringSplitOptions.RemoveEmptyEntries)
If keywords.Length > 0 Then
Dim strReplacement As String
strReplacement = "( tag = '" + keywords(0) + "'"
If keywords.Length > 1 Then
For i As Integer = 1 To keywords.Length - 1
strReplacement += " OR tag = '" + keywords(i) + "'"
Next
End If
strReplacement += " )"
SearchString = SearchString.Replace("{REPLACE-TAG}", strReplacement)
dt = tran.GetDataTable(SearchString)
End If

HIbernate + MSSQL query compatibility

I need to get the latest "version" of a Task object for a given objectUuid. The Task is identified by its objectUuid, taskName and createdTimestamp attributes.
I had the following HQL query:
select new list(te) from " + TaskEntity.class.getName() + " te
where
te.objectUuid = '" + domainObjectId + "' and
te.createdTimestamp = (
select max(te.createdTimestamp) from " + TaskEntity.class.getName() + " teSub
where teSub.objectUuid = te.objectUuid and teSub.taskName = te.taskName
)
which ran and produced the correct results on H2 (embedded) and MySQL.
However after installing this code in production to MS SQL Server I get the following error:
An aggregate may not appear in the WHERE clause unless it is in a
subquery contained in a HAVING clause or a select list, and the column
being aggregated is an outer reference.
I tried to rewrite the query but HQL doesn't seem to support subqueries properly. My latest attempt is something like:
select new list(te) from " + TaskEntity.class.getName() + " te
inner join (
select te2.objectUuid, te2.taskName, max(te2.createdTimestamp)
from " + TaskEntity.class.getName() + " te2
group by te2.objectUuid, te2.taskName
) teSub on
teSub.objectUuid = te.objectUuid and teSub.taskName = te.taskName
where
te.objectUuid = '" + domainObjectId + "'
but of course it fails at the "(" after the join statement.
Since this is a very frequent type of query I cannot believe there is no solution that works with HQL+MSSQL.
Uh-oh. Can this be a typo?
max(teSub.createdTimestamp)
instead of
max(te.createdTimestamp)
in the subquery.

How can I add more than 1 filter to persistence manager query in Java Google App Engine?

I'm using Java servlets to develop a Google App Engine application. I need to write up a query with more than 1 condition in the where clause. The commented out line below gives me query_parsing error. Is there a way to add more than one condition in the where clause?
String query = "select from " + Human.class.getName();
query += " where name == '" + request.getParameter("name") + "'";
//query += " and lastname == '" + request.getParameter("lastname") + "'";
List<Human> humans = (List<Human>) pm.newQuery(query).execute();
I know this is possible with JDO queries such as the below. However, my version is different. I'm using a String object to write up the query and then execute it with persistence manager (Please see above).
Query query = pm.newQuery(Employee.class);
query.setFilter("lastName == lastNameParam");
query.setOrdering("hireDate desc");
query.declareParameters("String lastNameParam");
In your first code snippet, I believe the issue is the word 'and', which should be '&&'. To have multiple filters, as in your second snippet, you would also use the '&&' operator.
String query = "select from " + Human.class.getName();
query += " where name == '" + request.getParameter("name") + "'";
query += " && lastname == '" + request.getParameter("lastname") + "'";
List<Human> humans = (List<Human>) pm.newQuery(query).execute();
or
Query query = pm.newQuery(Employee.class);
query.setFilter("lastName == lastNameParam && name == nameParam");
query.setOrdering("hireDate desc");
query.declareParameters("String lastNameParam");
query.declareParameters("String nameParam");

Resources