I want to find method-pairs that read or write the same field, for this i wrote this query:
match (c:Class)-[:DECLARES]->(m1:Method), (c)-[:DECLARES]-(m2:Method), (c)-[:DECLARES]-(f:Field), (m1)-[:WRITES|READS]->(f), (m2)-[:WRITES|READS]->(f)
return m1.name, m2.name, f.name
Now i have the problem, that there are several duplicates in the results.
I want every "m1.name" and "m2.name" pair to be unique. Is there a way to filter out results that are swaped versions of other results?
If you enforce a specific ordering of the Method nodes' native IDs, that will produce distinct Method name pairs (assuming method names are unique):
MATCH
(c:Class)-[:DECLARES]->(m1:Method),
(c)-[:DECLARES]-(m2:Method),
(c)-[:DECLARES]-(f:Field),
(m1)-[:WRITES|READS]->(f),
(m2)-[:WRITES|READS]->(f)
WHERE ID(m1) < ID(m2)
RETURN m1.name, m2.name, f.name
Example Realm relationship:
People.Dogs.FavouriteFoods
that are strictly one way -> RLMArrays
I have:
let result = RLMResult<People> from a previous operation.
and I have an array of FavouriteFood.IDs that a user selected
let selectedIDs: [String]
Now I am trying to filter/predicate this result, but instead of returning People, which I already have, I am trying to get out the FavouriteFood objects that intersect with the selectedIDs I can only find guides that explain how to sort/filter on RLMResults<People> where the result is People i.e. the same as the generic type on RLMResult.
My goal is to, in the end, construct a list where I can say "Out of the 14 FavouriteFoods Person A's Dogs have, 7 of them are in the selectedIDs list" etc. for Person B, C, D...
I want something like: "ANY dogs.favouriteFoods.ID in selectedIDs" but it should return all the FavouriteFoods matching the predicate for an individual Person, instead of all the People having Dogs having these particular favouriteFoods.
Is this possible to do as a predicate? Is there a way to flip the concept to ask for FavouriteFoods instead, or must I loop over all people, dogs, favouriteFoods and manually tally this up?
Thanks for any help given.
I'm trying to get a "Friend Recommendation" query. The nodes have the next sequence
(Node) - [FRIEND] - (Node) - [INFO] - (P_info)
where every node have a INFOrelation with a P_info node asociated. I can get a list of recommended friends of a Node but i need to include the P_info keys into recommended friends keys to return all together.
This is my query at the moment:
match (person:Account{_id:"185860469"})
match (person)-[:FRIEND]-()-[:FRIEND]-(potentialFriend)
where not (person)-[:FRIEND]-(potentialFriend)
match (potentialFriend)-[:INFO]-(information:P_info)
with person,potentialFriend, COUNT(*) AS friendsInCommon,information
where friendsInCommon > 5
return {user:person,recommend:collect(potentialFriend)},{info:information}
but the information of "info" is not asociated with "potentialFriend" at the response.
I want to do something like this:
return {user:person,collect(potentialFriend,information)} but i don't know if it's possible, cypher says:
Too many parameters for function 'collect'
thanks in advance.
I did it, just adding an additional WITH.I leave the answer in case someone helps
WITH person,{friend_id:potentialFriend._id,friend_name:information.name} AS Recommended_friend
RETURN person._id,collect(Recommended_friend)
this will return an unique response with person id and an array with all the recommended friends for him.
I want to replace the value of the 'Amount' key in a map (literal) with the sum of the existing 'Amount' value plus the new 'Amount' value such where both the 'type' and 'Price' match. The structure I have so far is:
WITH [{type:1, Orders:[{Price:10,Amount:100},{Price:11,Amount:200},{Price:12,Amount:300}]},
{type:2, Orders:[{Price:10,Amount:100},{Price:11,Amount:200},{Price:12,Amount:300}]},
{type:3, Orders:[{Price:10,Amount:100},{Price:11,Amount:200},{Price:12,Amount:300}]}] as ExistingOrders,
{type:2, Order:{Price:11,Amount:50}} as NewOrder
(I'm trying to get it to:)
RETURN [{type:1, Orders:[{Price:10,Amount:100},{Price:11,Amount:200},{Price:12,Amount:300}]},
{type:2, Orders:[{Price:10,Amount:100},{Price:11,Amount:250},{Price:12,Amount:300}]},
{type:3, Orders:[{Price:10,Amount:100},{Price:11,Amount:200},{Price:12,Amount:300}]}] as CombinedOrders
If there is no existing NewOrder.type and NewOrder.Price then it should obviously insert the new record rather than add it together.
Sorry, this is possibly really straight forward, but I'm not very good at this yet.
thanks
Edit:
I should add, that I have been able to get this working for a simpler map structure as such:
WITH [{type:1, Amount:100},{type:2, Amount:200},{type:3, Amount:300}] as ExistingOrders,
{type:2, Amount:50} as NewValue
RETURN reduce(map=filter(p in ExistingOrders where not p.type=NewValue.type),x in [(filter(p2 in ExistingOrders where p2.type=NewValue.type)[0])]|CASE x WHEN null THEN NewValue ELSE {type:x.type,Amount:x.Amount+NewValue.Amount} END+map) as CombinedOrders
But I'm struggling I think because of the Orders[array] in my first example.
I believe you are just trying to update the value of the appropriate Amount in ExistingOrders.
The following query is legal Cypher, and should normally work:
WITH ExistingOrders, NewOrder, [x IN ExistingOrders WHERE x.type = NewOrder.type | x.Orders] AS eo
FOREACH (y IN eo |
SET y.Amount = y.Amount + CASE WHEN y.Price = NewOrder.Order.Price THEN NewOrder.Order.Amount ELSE 0 END
)
However, the above query produces a (somewhat) funny ThisShouldNotHappenError error with the message:
Developer: Stefan claims that: This should be a node or a relationship
What the message is trying to say (in obtuse fashion) is that you are not using the neo4j DB in the right way. Your properties are way too complicated, and should be separated out into nodes and relationships.
So, I will a proposed data model that does just that. Here is how you can create nodes and relationships that represent the same data as ExistingOrders:
CREATE (t1:Type {id:1}), (t2:Type {id:2}), (t3:Type {id:3}),
(t1)-[:HAS_ORDER]->(:Order {Price:10,Amount:100}),
(t1)-[:HAS_ORDER]->(:Order {Price:11,Amount:200}),
(t1)-[:HAS_ORDER]->(:Order {Price:12,Amount:300}),
(t2)-[:HAS_ORDER]->(:Order {Price:10,Amount:100}),
(t2)-[:HAS_ORDER]->(:Order {Price:11,Amount:200}),
(t2)-[:HAS_ORDER]->(:Order {Price:12,Amount:300}),
(t3)-[:HAS_ORDER]->(:Order {Price:10,Amount:100}),
(t3)-[:HAS_ORDER]->(:Order {Price:11,Amount:200}),
(t3)-[:HAS_ORDER]->(:Order {Price:12,Amount:300});
And here is a query that will update the correct Amount:
WITH {type:2, Order:{Price:11,Amount:50}} as NewOrder
MATCH (t:Type)-[:HAS_ORDER]->(o:Order)
WHERE t.id = NewOrder.type AND o.Price = NewOrder.Order.Price
SET o.Amount = o.Amount + NewOrder.Order.Amount
RETURN t.id, o.Price, o.Amount;
There's two parts to your question - one with a simple answer, and a second part that doesn't make sense. Let me take the simple one first!
As far as I can tell, it seems you're asking how to concatenate a new map on to a collection of maps. So, how to add a new item in an array. Just use + like this simple example:
return [{item:1}, {item:2}] + [{item:3}];
Note that the single item we're adding at the end isn't a map, but a collection with only one item.
So for your query:
RETURN [
{type:1, Orders:[{Price:10,Amount:100},
{Price:11,Amount:200},
{Price:12,Amount:300}]},
{type:2, Orders:[{Price:10,Amount:100},
{Price:11,Amount:**250**},
{Price:12,Amount:300}]}]
+
[{type:3, Orders:[{Price:10,Amount:100},
{Price:11,Amount:200},{Price:12,Amount:300}]}]
as **CombinedOrders**
Should do the trick.
Or you could maybe do it a bit cleaner, like this:
WITH [{type:1, Orders:[{Price:10,Amount:100},{Price:11,Amount:200},{Price:12,Amount:300}]},
{type:2, Orders:[{Price:10,Amount:100},{Price:11,Amount:200},{Price:12,Amount:300}]},
{type:3, Orders:[{Price:10,Amount:100},{Price:11,Amount:200},{Price:12,Amount:300}]}] as ExistingOrders,
{type:2, Order:{Price:11,Amount:50}} as NewOrder
RETURN ExistingOrders + [NewOrder];
OK now for the part that doesn't make sense. In your example, it looks like you want to modify the map inside of the collection. But you have two {type:2} maps in there, and you're looking to merge them into something with one resulting {type:3} map in the output that you're asking for. If you need to deconflict map entries and change what the map entry ought to be, it might be that cypher isn't your best choice for that kind of query.
I figured it out:
WITH [{type:1, Orders:[{Price:10,Amount:100},{Price:11,Amount:200},Price:12,Amount:300}]},{type:2, Orders:[{Price:10,Amount:100},{Price:11,Amount:200},{Price:12,Amount:300}]},{type:3, Orders:[{Price:10,Amount:100},{Price:11,Amount:200},{Price:12,Amount:300}]}] as ExistingOrders,{type:2, Orders:[{Price:11,Amount:50}]} as NewOrder
RETURN
reduce(map=filter(p in ExistingOrders where not p.type=NewOrder.type),
x in [(filter(p2 in ExistingOrders where p2.type=NewOrder.type)[0])]|
CASE x
WHEN null THEN NewOrder
ELSE {type:x.type, Orders:[
reduce(map2=filter(p3 in x.Orders where not (p3.Price=(NewOrder.Orders[0]).Price)),
x2 in [filter(p4 in x.Orders where p4.Price=(NewOrder.Orders[0]).Price)[0]]|
CASE x2
WHEN null THEN NewOrder.Orders[0]
ELSE {Price:x2.Price, Amount:x2.Amount+(NewOrder.Orders[0]).Amount}
END+map2 )]} END+map) as CombinedOrders
...using nested Reduce functions.
So, to start with it combines a list of orders without matching type, with a list of those orders (actually, just one) with a matching type. For those latter ExistingOrders (with type that matches the NewOrder) it does a similar thing with Price in the nested reduce function and combines non-matching Prices with matching Prices, adding the Amount in the latter case.