Update field in table defined as a list of symbols - symbols

I have the following table:
q)t:([]col:`a`b`c; vals:((`abc`def);(enlist `abc);(`$())))
q)t
col vals
---------------
a `abc`def
b ,`abc
c `symbol$()
I want to update the entry where col=c, that is the empty list of symbols, but I get a `length error when trying the following query:
update vals:(enlist `unknown) from t where 0=count each vals
The goal is then to do an ungroup t and don't lose the data where vals=`symbol$(), as currently the ungroup is making me losing some rows.

I guess you got the 'length error when you updated some other table, not the one you gave as an example. Your sample code works just fine. The reason why it works on t which has only one row where 0=count each vals but fails on tables which have more than one row satisfying the where condition is the update needs the size of a list of updates to match the target. If a table has more than one row with empty vals an update will fail because you provide a list with only one new value.
By the way, if a column were a vector (i.e. a simple list of atoms) then providing an atom as an update would work because atoms are extended to match vectors. But vectors don't.
One way to deal with that is provide a conforming list as Rob suggested in his answer or, as an alternative, use join with each-left:
q)update vals:(vals,\:`unknown) from 6#t where 0=count each vals
col vals
-------------
a `abc`def
b ,`abc
c ,`unknown
a `abc`def
b ,`abc
c ,`unknown

To replace your empty symbol lists in the column vals with `unknown, you could use something like:
q)t:([]col:`a`b`c; vals:((`abc`def);(enlist `abc);(`$())))
q)t:6#t
update vals:count[i]#enlist enlist `unknown from t where 0=count each vals
Output:
col vals
-------------
a `abc`def
b ,`abc
c ,`unknown
a `abc`def
b ,`abc
c ,`unknown
which uses your approach of finding the values in val which have a count of 0.
Or alternatively, you could use something like:
update vals:{$[x~`symbol$();enlist `unknown;x]}'[vals] from t
Same output as first example:
col vals
-------------
a `abc`def
b ,`abc
c ,`unknown
a `abc`def
b ,`abc
c ,`unknown
This approach just checks if the value of val is empty or not and replaces its value of val with `unknown accordingly.

You could also consider making your own ungroup function if that's ultimately the problem you're trying to solve:
q)raze{$[count f:flip x;f;enlist first each x]}'[t]
col vals
--------
a abc
a def
b abc
c

Related

Esper statement to check, if A is followed by B without any other As in between

I have the two events: A and B. Everytime A occurs, B have to occur afterwards without any As in between.
Has anybody got an idea, how to implement this? I thought about something like
pattern[every A -> A until B]
But this statement is true, even if A is followed B without any other As in between. But it should only be true in case of AAB or AAAAB and so on..
Thank you for your help.
One possible solution is the pattern
A -> (A and not B)
Doing so the query is only true, when the rule is violated. But if it is fulfilled, I don't get any hint.
Is there a better solution?
Match-recognize pattern matching has immediately-followed-by-semantics. You could do something like this:
create schema A();
create schema B();
select * from pattern[every a=A or every b=B]
match_recognize (
measures p1 as a, p2 as b
pattern (p1 p2)
define
p1 as typeof(p1.a) = 'A',
p2 as typeof(p2.b) = 'B'
)
Or you could use an approach with insert-into.
insert into CombinedStream select id, 'a' as type from A;
insert into CombinedStream select id, 'b' as type from B;
select * from CombinedStream
match_recognize (
measures a as a, b as b
pattern (a b)
define
a as a.type = 'A',
b as b.type = 'B'
)
And when you want to go with EPL pattern langague that can also work. EPL patterns always add and remove from filter indexes and that can be less performant depending on how many incoming events are matched and unmatched/discarded (i.e. per-event-analysis versus need-in-a-haystack)
every A -> (B and not A) // read: every A followed by B and not A

Neo4j - Find missing node to complete circle

I am trying to get a query that starting from a node, it returns the missing node that, when making a new relation to it, would complete a circle. Also it should respond which is the node that, if the circle is close, will end up having a relationship with the input node. Example:
Let's say I have B -> C and C -> A. In this case, if I pass A as input, I would like to receive { newRelationToMake: B, relationToInputNode: C } as a result, since connecting A -> B will result in a closed circle ABC and the relation that the node A will be having will come from C.
Ideally, this query should work for a maximum of n depths. For example for a depth of 4, with relations B -> C, C -> D and D -> A, and I pass A as input, I would need to receive { newRelationToMake: C, relationToInputNode: D} (since if I connect A -> C I close the ACD circle) but also receive {newRelationToMake: B, relationToInputNode: D }(since if I connect A -> B I would close the ABCD circle).
Is there any query to get this information?
Thanks in advance!
You are basically asking for all distinct nodes on paths leading to A, but which are not directly connected to A.
Here is one approach (assuming the nodes all have a Foo label and the relationships all have the BAR type):
MATCH (f:Foo)-[:BAR*2..]->(a:Foo)
WHERE a.id = 'A' AND NOT EXISTS((f)-[:BAR]->(a))
RETURN DISTINCT f AS missingNodes
The variable-length relationship pattern [:BAR*2..] looks for all paths of length 2 or more.

cypher distinct is returning duplicate using with parameter

MATCH (c:someNode) WHERE LOWER(c.erpId) contains (LOWER("1"))
OR LOWER(c.constructionYear) contains (LOWER("1"))
OR LOWER(c.label) contains (LOWER("1"))
OR LOWER(c.name) contains (LOWER("1"))
OR LOWER(c.description) contains (LOWER("1"))with collect(distinct c) as rows, count(c) as total
MATCH (c:someNode)-[adtype:OFFICIAL_someNode_ADDRESS]->(ad:anotherObject)
WHERE toString(ad.streetAddress) contains "1"
OR toString(ad.postalCity) contains "1"
with distinct rows+collect( c) as rows, count(c) +total as total
UNWIND rows AS part
RETURN part order by part.name SKIP 20 Limit 20
When I run the following cypher query it returns duplicate results. Also it the skip does not seem to work. What am I doing worng
When you use WITH DISTINCT a, b, c (or RETURN DISTINCT a, b, c), that just means that you want each resulting record ({a: ..., b: ..., c: ...}) to be distinct -- it does not affect in any way the contents of any lists that may be part of a, b, or c.
Below is a simplified query that might work for you. It does not use the LOWER() and TOSTRING() functions at all, as they appear to be superfluous. It also only uses a single MATCH/WHERE pair to find all the the nodes of interest. The pattern comprehension syntax is used as part of the WHERE clause to get a non-empty list of true value(s) iff there are any anotherObject node(s) of interest. Notice that DISTINCT is not needed.
MATCH (c:someNode)
WHERE
ANY(
x IN [c.erpId, c.constructionYear, c.label, c.name, c.description]
WHERE x CONTAINS "1") OR
[(c)-[:OFFICIAL_someNode_ADDRESS]->(ad:anotherObject)
WHERE ad.streetAddress CONTAINS "1" OR ad.postalCity CONTAINS "1"
| true][0]
RETURN c AS part
ORDER BY part.name SKIP 20 LIMIT 20;

Neo4j: How to fix one of the node in match clause?

For clauses like MATCH (a:Address)-[:BelongTo]->(w1:Wallet), (a)-[r0:BelongTo]->(w2:Wallet) WHERE ID(w1)>ID(w2) WITH w1, w2..., is it possible to make sure that ex. w1 is always a fixed node? If yes, is it possible to decide on the node by choosing the node having ex. the minimum value for a certain property over all the nodes which could also be w1?
More concretely, for example, an address a belong to wallet a, b, c with a>b>c in terms of ID. Then normally these rows of result will be returned:
w1 w2
--------
a b
b c
a c
I only want these two rows of result to be returned:
w1 w2
--------
a b
a c
Note: I want the query try to get every pair of wallets to both an address belongs to. All addresses which belongs to two or more wallet should be included in return if a is returned.
So for example, If there are two addresses which belong to three different wallets, what would the query you posted do?
More concretely, if addresses a1 and a2 belong to b1, c1, d1 and b2, c2, d2 respectively, (with b1 > c1 > d1> b2> c2>d2 in terms of id)
I want it to return:
a w1 w2
-----------
a1 b1 c1
a1 b1 d1
a2 b2 c2
a2 b2 d2
Is it possible?
Yes, you can do this by finding (for each a:Address), the :Wallet with the minimum id. After you match to this :Wallet, you can match to all the other :Wallets.
MATCH (a:Address)-[:BelongTo]->(w1:Wallet)
WITH a, min(id(w1)) as minId
// since we have the minId, we can do a fast lookup of the node
MATCH (minW:Wallet)
WHERE id(minW) = minId
// now get all the others
MATCH (a)-[:BelongTo]->(w2:Wallet)
WHERE minW <> w2
...
If you don't care how the fixed node is taken, and if it only matters for the duration of the query, it may be easier to collect all the :Wallet nodes, take the first node in the collection, and then UNWIND the rest into rows and continue the query:
MATCH (a:Address)-[:BelongTo]->(w:Wallet)
WITH a, collect(w) as wallets
WITH a, head(wallets) as w1, wallets
UNWIND tail(wallets) as w2
...

neo4j distinct two columns

How to return two different columns with cypher in Neo4j? The query which I've got is that:
MATCH (a:Person)-[r:WorksFOR]->(b:Boss), (c:Boss)<-[r2:WorksFOR]-(d:Person)
WHERE b.sex = c.sex
RETURN a, d;
And it returns:
a d
John Will
Will John
I want to get rid of one of the column.
OP needs to reword the question to clarify OP wants to get rid of one of the rows.
Here's a query that does that:
MATCH (a:Person)-[r:WorksFOR]->(b:Boss), (c:Boss)<-[r2:WorksFOR]-(d:Person)
WHERE b.name < c.name AND
b.sex = c.sex AND
b <> c
RETURN a, d;
The problem with your query is that b and c can match any Boss. To force them to match in one order, I've added b.name < c.name. The order doesn't matter, this just forces it to match one way, but not the other. I've added b <> c because you have to handle the case where they work for the same boss, which I don't think you want.
Once you add the ordering, the boss matching (b and c) can only happen one way, not the other way, so your second row of results gets eliminated.

Resources