如何在Cypher的地图中添加现有值?

时间:2015-01-27 17:26:15

标签: neo4j cypher

我想替换' Amount'的价值。键入地图(字面值),其中包含现有'金额'价值加上新的金额'这样的价值,如果'类型'和' Price'比赛。我到目前为止的结构是:

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 [{​​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 < / p>

如果没有现有的NewOrder.type和NewOrder.Price,那么显然应该插入新记录而不是将它们加在一起。

对不起,这可能非常简单,但我还不是很擅长。

感谢

修改

我应该补充一点,我已经能够使这个更简单的地图结构:

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

但是我觉得因为我的第一个例子中的Orders [数组]而苦苦挣扎。

3 个答案:

答案 0 :(得分:2)

我认为您只是想更新Amount中相应ExistingOrders的值。

以下查询是合法的Cypher,应该正常工作:

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
)

但是,上述查询会在消息中产生(有些)有趣的ThisShouldNotHappenError错误:

  

开发人员:Stefan声称:这应该是节点或关系

消息试图说的是(以钝的方式)是你没有以正确的方式使用neo4j DB。您的属性太复杂了,应该分成节点和关系。

所以,我将提出一个能够做到这一点的数据模型。以下是如何创建表示与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});

这是一个更新正确的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;

答案 1 :(得分:1)

你的问题分为两部分 - 一部分是简单的答案,第二部分是没有意义的。让我先拿一个简单的!

据我所知,您似乎在询问如何将新地图连接到地图集合。那么,如何在数组中添加新项。只需使用+就像这个简单的例子:

return [{item:1}, {item:2}] + [{item:3}];

请注意,我们在末尾添加的单个项目不是地图,而是仅包含一个项目的集合。

所以对于你的查询:

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**

应该做的伎俩。

或者你也许可以做得更清洁,像这样:

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];

现在好了,对于没有意义的部分。在您的示例中,您似乎想要修改集合内的地图。但是你有两张{type:2}地图,你正在寻找将它们合并到你要求的输出中有一个{type:3}地图的地图。如果您需要解除冲突地图条目并更改地图条目应该是什么,那么可能是cypher不是您进行此类查询的最佳选择。

答案 2 :(得分:0)

我明白了:

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

...使用嵌套的Reduce函数。

因此,首先,它将订单列表与匹配type组合在一起,列出了这些订单(实际上只有一个) with a匹配type。对于后者ExistingOrderstypeNewOrder匹配),它在嵌套Price函数中与reduce做类似的事情并组合不匹配{ {1}}匹配Price s,在后一种情况下添加Price