I have list property [1,2,2,0]. The value is the list default to type of long. To convert to a list of type integer I am using
apoc.convert.toIntList([1,2,2,0])
but the result is still a list of type long.....however
apoc.convert.toStringList([1,2,2,0])
does result in a list of strings. This my query:
MERGE (bs:Bslot {date: $date})
ON CREATE
SET bs.slots = [1,2,2,0]
RETURN {slots: apoc.convert.toIntList(bs.slots)}
What am I doing wrong here?
It is working as expected; see below example:
WITH [1,2,2,0.99] as slots
RETURN {slots: apoc.convert.toIntList(slots)}
Result:
╒════════════════════════════════════════╕
│"{slots: apoc.convert.toIntList(slots)}"│
╞════════════════════════════════════════╡
│{"slots":[1,2,2,0]} │
└────────────────────────────────────────┘
Notice that 0.99 (float) becomes an integer.
In your example; MERGE will not update slots property when that node Bslot with date equals $date. It is because it will only set the value of slots to [1,2,2,0] if that node is new (create).
Related
I have the following structure for a Grid and wanted to know how to sort a column based on the Integer values of the Strings. The data provider is not flexible to change, so I have to sort with some kind of intermediary step:
Grid<String[]> grid = new Grid<>();
...
grid.addColumn(str -> str[columnIndex]).setHeader("sample").setKey("integercolumn").setSortable(true);
...
GridSortOrder<String> order = new GridSortOrder<>(grid.getColumnByKey("integercolumn"), SortDirection.DESCENDING);
grid.sort(Arrays.asList(order));
This sorts two digit numbers properly but not one digit or 3+.
You can define a custom comparator on the column that is used for sorting its values. In your case the comparator needs to extract the column-specific value from the array, and then convert it to an int:
grid.addColumn(row -> row[columnIndex])
.setHeader("sample")
.setKey("integercolumn")
.setSortable(true)
.setComparator(row -> Integer.parseInt(row[columnIndex]));
See https://vaadin.com/docs/latest/components/grid/#specifying-the-sort-property.
Using Neo4j.
I would like to add a integer number to values already existing in properties of several relationships that I call this way:
MATCH x=(()-[y]->(s:SOL{PRB:"Taking time"})) SET y.points=+2
But it doesn't add anything, just replace by 2 the value I want to incremente.
To achieve this use
SET y.points = y.points + 2
From your original question it looks like you were trying to use the Addition Assignment operator which exists in lots of languages (e.g. python, type/javascript, C#, etc.). However, in cypher += is a little different and is designed to do this in a way which allows you to add or update properties to or on entire nodes or relationships based on a mapping.
If you had a parameter like the below (copy this into the neo4j browser to create a param).
:param someMapping: {a:1, b:2}
The query below would create a property b on the node with value 2, and set the value of property a on that node to 1.
MATCH (n:SomeLabel) WHERE n.a = 0
SET n+= $someMapping
RETURN n
I'm using NEO4J 3.0 and it seems that HAS function was removed.
Type of myrelationship is a date and I'm looking to retrieve all relation between two dates such as my property "a" is greater than certain value.
How can I test this using NEO4j
Thank you
[EDITED to add info from comments]
I have tried this:
MATCH p=(n:origin)-[r]->()
WHERE r>'2015-01'
RETURN AVG(r.amount) as totalamout;
I created relationship per date and each one has a property, amount, and I am looking to compute the average amount for certain period. As example, average amount since 2015-04.
To answer the issue raised by your first sentence: in neo4j 3.x, the HAS() function was replaced by EXISTS().
[UPDATE 1]
This version of your query should work:
MATCH p=(n:origin)-[r]->()
WHERE TYPE(r) > '2015-01'
RETURN AVG(r.amount) as totalamout;
However, it is a bad idea to give your relationships different types based on a date. It is better to just use a date property.
[UPDATE 2]
If you changed your data model to add a date property to your relationships (to which I will give the type FOO), then the following query will find the average amount, per p, of all the relationships whose date is after 2015-01 (assuming that all your dates follow the same strict YYYY-MM pattern):
MATCH p=(n:origin)-[r:FOO]->()
WHERE r.date > '2015-01'
RETURN p, AVG(r.amount) as avg_amout;
guys, i'm trying to get values from the next query
SELECT X.val, X.tdate
FROM
XMLTABLE ('$d/IRR' passing XMLPARSE(DOCUMENT '<IRR><value>2</value><tdate>2014-06-05</tdate><value>4</value><tdate>2014-08-05</tdate></IRR>') as "d"
COLUMNS
val DOUBLE PATH './value',
tdate DATE PATH './tdate' ) AS X;
but I always get the error:
An expression of data type "( item(), item()+ )" cannot be used when
the data type "DATE" is expected in the context
at the same time everything works fine if there is only one value and date like
SELECT X.val, X.tdate
FROM
XMLTABLE ('$d/IRR' passing XMLPARSE(DOCUMENT '<IRR><value>2</value><tdate>2014-06-05</tdate></IRR>') as "d"
COLUMNS
val DOUBLE PATH './value',
tdate DATE PATH './tdate' ) AS X;
And as I understand here it's because XMLTABLE waits only for 1 value and it cann't parse the doc if there are few of them
What's more it works fine if there is only 1 column need to be returned like this even though there are a few values:
SELECT X.tdate
FROM
XMLTABLE ('$d/IRR/tdate' passing XMLPARSE(DOCUMENT '<IRR><value>2</value><tdate>2014-06-05</tdate><value>4</value><tdate>2014-08-05</tdate></IRR>') as "d"
COLUMNS
tdate DATE PATH '.' ) AS X;
So this query returns both dates.
tdate
2014-06-05
2014-08-05
So is there any way to return both columns with multiply values in the same query?
e.g.
val tdate
2 2014-06-05
4 2014-08-05
Note: that is the representation of the xml document which is passed in my procedure (it could contain more than 2 values)
<IRR><value>2</value><tdate>2014-06-05</tdate><value>4</value><tdate>2014-08-05</tdate></IRR>
XMLTABLE() can return a special ordinality column, containing the sequential number of each row. You can use it to do something like:
WITH t(x) AS (VALUES XMLPARSE(DOCUMENT '<IRR><value>2</value><tdate>2014-06-05</tdate><value>4</value><tdate>2014-08-05</tdate></IRR>'))
SELECT x1.value, x2.tdate
FROM
t,
XMLTABLE ('$X//value'
COLUMNS
value INT PATH '.',
idx FOR ORDINALITY) AS X1,
XMLTABLE ('$X//tdate'
COLUMNS
tdate DATE PATH '.',
idx FOR ORDINALITY) AS X2
WHERE x1.idx = x2.idx
ORDER BY 2
This assumes that the XML parser preserves the element order, which, although not explicitly documented, seems to be the case with all parsers I've worked with.
Ideally you should rethink your XML schema, for example, passing tdate as an attribute of value (or vice versa).
I have nodes within a the graph with property pathway storing an array of of values ranging from
path:ko00030
path:ko00010
.
.
path:koXXXXX
As an example, (i'm going to post in the batch import format:https://github.com/jexp/batch-import/tree/20)
ko:string:koid name definition l:label pathway:string_array pathway.name:string_array
ko:K00001 E1.1.1.1, adh alcohol dehydrogenase [EC:1.1.1.1] ko path:ko00010|path:ko00071|path:ko00350|path:ko00625|path:ko00626|path:ko00641|path:ko00830
the subsequent nodes might have a different combination of pathway values.
How do i query using CYPHER to retrieve all nodes with path:ko00010 in pathway
the closest i've gotten is using the solution provided for a different problem:
How to check array property in neo4j?
match (n:ko)--cpd
Where has(n.pathway) and all ( m in n.pathway where m in ["path:ko00010"])
return n,cpd;
but here only nodes with pathways matching exactly to the list provided are returned.
ie. if i were to query path:ko00010 like in the example above, I'll only be able to retrieve nodes holding path:ko00010 as the only element in the pathway property and not nodes containing path:ko00010 as well as other path:koXXXXX
In your query the extension of the predicate ALL is all the values in the property array, meaning that your query will only return those cases where every value in the pathway property array are found in the literal array ["path:ko00010"]. If I understand you right you want the opposite, you want to test that all values in the literal array ["path:ko00010"] are found in the property array pathway. If that's indeed what you want you can just switch their places, your WHERE clause will then be
WHERE HAS(n.pathway) AND ALL (m IN ["path:ko00010"] WHERE m IN n.pathway)
It is not strictly correct to say that your query only matches cases where the array you ask for and the property array are exactly the same. You could have had more than one value in the literal array, something like ["path:ko00010","path:ko00020"], and nodes with only one one of those values in their pathway array would also have matched–as long as all values in the property array could be found in the literal array. Conversely, with the altered WHERE filter that I've suggested, the query will match any node that has all of the values of the literal array in their pathway property.
If you want to filter the matched patterns with an array of values where all of them have to be present, this is good. In your example you only use one value, however, and for those queries there is no reason to use an array and the ALL predicate. You can simply do
WHERE HAS(n.pathway) and "path:ko00010" IN n.pathway
If in some context you want to include results where any of a set of values are found in the pathway property array you can just switch from ALL to ANY
WHERE HAS(n.pathway) AND ANY (m IN ["path:ko00010","path:ko00020"] WHERE m IN n.pathway)
Also, you probably don't need to check for the presence of the pathway property, unless you have some special use for it you should be fine without the HAS(n.pathway).
And once you've got the queries working right, try to switch out literal strings and arrays for parameters!
WHERE {value} IN n.pathway
// or
WHERE ALL (m IN {value_array} WHERE m IN n.pathway)
// or
WHERE ANY (m IN {value_array} WHERE m IN n.pathway)