Cypher zip collections - neo4j

If I have two collections, how might I zip them together?
with [1,2,3] as nums, ['a', 'b', 'c'] as letters
... wat do? ...
return zipped // [{a: 1}, {b: 2}, {c: 3}]

It may not be possible to dynamically assign map keys (e.g., using the items in letters). But this query will return something similar to what you want (using collections instead of maps):
WITH [1,2,3] as nums, ['a', 'b', 'c'] as letters
RETURN EXTRACT(i IN RANGE(0, LENGTH(nums) - 1) | [letters[i], nums[i]]) AS result;
The result is:
[["a",1],["b",2],["c",3]]

Related

(Neo4j, Cypher) How to set incremental number to relationships?

i'm using neo4j. what i'd like to do is to create a root node for search result and to create relationships from root node to search result nodes. and I'd like to set incremental number to each relationship's property.
if possible, with one query.
Sorry for not explaining enough.
This is what I'd like to do.
Any more concise way?
// create test data
WITH RANGE(0, 99) AS indexes,
['Paul', 'Bley', 'Bill', 'Evans', 'Robert', 'Glasper', 'Chihiro', 'Yamanaka', 'Fred', 'Hersch'] AS names
UNWIND indexes AS index
CREATE (p:Person { index: index, name: (names[index%10] + toString(index)) });
// create 'Results' node with relationships to search result 'Person' nodes.
// 'SEARCH_RESULT' relationships have 'order' and 'orderBy' properties.
CREATE(x:Results{ts: TIMESTAMP()})
WITH x
MATCH(p:Person)
WHERE p.name contains '1'
MERGE(x)-[r:SEARCH_RESULT]->(p)
WITH x, r, p
MATCH (x)-[r]->(p)
WITH x, r, p
ORDER BY p.name desc
WITH RANGE(0, COUNT(r)-1) AS indexes, COLLECT(r) AS rels
UNWIND indexes AS i
SET (rels[i]).order = i
SET (rels[i]).orderBy = 'name'
RETURN rels;
// validate
MATCH(x:Results)-[r:SEARCH_RESULT]->(p:Person)
RETURN r, p.name ORDER BY r.order;

Which table to act on

Say I have two tables xs and ys in the database; both xs, ys have two columns id, name, and several rows: where for both tables the first row has entries
id = 1, name = "John".
Now in rails,
X.find(1)
and
Y.find(1)
returns the same hash:
{id: 1, name: "John"}
Now both
X.find(1)
and
Y.find(1)
has method destroy, which should not be a standard ruby hash method. I had to make myself content with the idea that rails somehow provided these hashes with this method.
But how
{id: 1, name: "John"}.destroy
knows which of the tables xs, ys should have its first row destroyed?

neo4j: What is the syntax to set cypher query parameters in the browser interface?

I am trying to run queries from the neo4j browser to reproduce results from my neo4j-javascript-driver client.
What is the syntax for defining query parameters in the neo4j b
I recently attended a neo4j training session in NYC where the trainer (David Fauth) did this, unfortunately, I did not take notes on it, since I figured that I could read-up on this online...but no success.
In neo4j-browser you need type for example:
:params {nodes: [{name: "John", age: 18}, {name: "Phill", age: 23}]}
Then you can use params as usual:
UNWIND {nodes} as node
MERGE (A:User {name: node.name, age: node.age})
RETURN A
For clear params in neo4j-browser type :params {}.
For additional help type :help params.
In Neo4j-3.3.4, the cypher likes this:
:param nodes: [{name: 'John', age: 18}, {name: 'Phill', age: 23}]
Neo4j Browser result:
here
In Neo4j Browser 3.5+ you can use the Cypher Shell parameter syntax, documented here: https://neo4j.com/docs/operations-manual/3.5/tools/cypher-shell/#cypher-shell-parameters
:param name => expression
The expression must be kept on a single line.
The expression could be a scalar or a list:
:param foo => ['a', 'b', 'c']
Maps can't be used directly with this syntax as of Neo4j 4.1. You can wrap them into a list:
:param foo => [{name: 'Alice', age: 38, address: {city: 'London', residential: true}}]
Or you can use :params:
:params {foo: {name: 'Alice', age: 38, address: {city: 'London', residential: true}}}
In Neo4j Browser 3.5+ you can use
:params param_name => 'param_value'
The basic cases:
Set singe variable value mytext="Hello": :param mytext => "Hello"
set dictionary values attr={"oid":1, "text":"Hello"}:
:param attr => ({oid: 1, text:"Hello"})
Cypher usage:
MATCH (x) WHERE x.a = $mytext RETURN x
set a value MATCH (x) WHERE x.a = $attr.oid SET x.b = $attr.text
set multiple values MATCH (x) WHERE ... SET x = $attr

Active record: filter on distinct value

I have several entries in a table in my RoR app:
{id: 1, item_id: a, ...}
{id: 2, item_id: a, ...}
{id: 3, item_id: a, ...}
{id: 4, item_id: b, ...}
{id: 5, item_id: b, ...}
{id: 6, item_id: c, ...}
{id: 7, item_id: d, ...}
{id: 8, item_id: d, ...}
I would like to create a query that filters on distinct item_id and returns the first matching entry, so that the result would be
{id: 1, item_id: a, ...}
{id: 4, item_id: b, ...}
{id: 6, item_id: c, ...}
{id: 7, item_id: d, ...}
When using
select(:item_id).distinct
I cannot access the other attributes of the entries. How can this be accomplished?
If you just want to get the lowest id for every item_id, you could use an aggregate query to retrieve these ids:
grouped_with_min_id = Model.group(:item_id).minimum(:id)
rows = Model.find(grouped_with_min_id.map(&:id))
This may not be the most efficient solution as it uses two queries. But other methods will probably require you to use Model.find_by_sql and write your own sql.
Disclaimer: I did not try that out.

match in clause in cypher

How can I do an match in clause in cypher
e.g. I'd like to find movies with ids 1, 2, or 3.
match (m:movie {movie_id:("1","2","3")}) return m
if you were going against an auto index the syntax was
START n=node:node_auto_index('movie_id:("123", "456", "789")')
how is this different against a match clause
The idea is that you can do:
MATCH (m:movie)
WHERE m.movie_id in ["1", "2", "3"]
However, this will not use the index as of 2.0.1. This is a missing feature in the new label indexes that I hope will be resolved soon. https://github.com/neo4j/neo4j/issues/861
I've found a (somewhat ugly) temporary workaround for this.
The following query doesn't make use of an index on Person(name):
match (p:Person)... where p.name in ['JOHN', 'BOB'] return ...;
So one option is to repeat the entire query n times:
match (p:Person)... where p.name = 'JOHN' return ...
union
match (p:Person)... where p.name = 'BOB' return ...
If this is undesirable then another option is to repeat just a small query for the id n times:
match (p:Person) where p.name ='JOHN' return id(p)
union
match (p:Person) where p.name ='BOB' return id(p);
and then perform a second query using the results of the first:
match (p:Person)... where id(p) in [8,16,75,7] return ...;
Is there a way to combine these into a single query? Can a union be nested inside another query?

Resources