如何添加到 Cypher 地图中的现有值?
How to add to an existing value in a map in Cypher?
我想用现有 'Amount' 值加上新的 'Amount' 值的总和来替换地图(文字)中 'Amount' 键的值,例如'type' 和 '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}]}] 作为 CombinedOrders
如果不存在 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
但我觉得我正在努力,因为第一个示例中的订单[数组]。
您的问题有两个部分 - 一个有简单的答案,第二个部分没有意义。先说简单的吧!
据我所知,您似乎在询问如何将新地图连接到地图集合。那么,如何在数组中添加一个新项。就像这个简单的例子一样使用 +
:
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 可能不是您的最佳选择。
我相信您只是想更新 ExistingOrders
中适当 Amount
的值。
以下查询是合法的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
错误消息:
Developer: Stefan claims that: This should be a node or a relationship
该消息试图表达的意思是(以迟钝的方式)您没有以正确的方式使用 neo4j 数据库。您的属性太复杂了,应该分成节点和关系。
所以,我将提出一个能够做到这一点的数据模型。以下是如何创建表示与 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;
我想通了:
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
的订单列表与这些订单的列表(实际上只有一个)与匹配type
。对于后者 ExistingOrders
(type
与 NewOrder
匹配),它在嵌套 reduce
函数中与 Price
做类似的事情,并结合不匹配的 Price
s 匹配 Price
s,在后一种情况下添加 Amount
。
我想用现有 'Amount' 值加上新的 'Amount' 值的总和来替换地图(文字)中 'Amount' 键的值,例如'type' 和 '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}]}] 作为 CombinedOrders
如果不存在 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
但我觉得我正在努力,因为第一个示例中的订单[数组]。
您的问题有两个部分 - 一个有简单的答案,第二个部分没有意义。先说简单的吧!
据我所知,您似乎在询问如何将新地图连接到地图集合。那么,如何在数组中添加一个新项。就像这个简单的例子一样使用 +
:
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 可能不是您的最佳选择。
我相信您只是想更新 ExistingOrders
中适当 Amount
的值。
以下查询是合法的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
错误消息:
Developer: Stefan claims that: This should be a node or a relationship
该消息试图表达的意思是(以迟钝的方式)您没有以正确的方式使用 neo4j 数据库。您的属性太复杂了,应该分成节点和关系。
所以,我将提出一个能够做到这一点的数据模型。以下是如何创建表示与 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;
我想通了:
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
的订单列表与这些订单的列表(实际上只有一个)与匹配type
。对于后者 ExistingOrders
(type
与 NewOrder
匹配),它在嵌套 reduce
函数中与 Price
做类似的事情,并结合不匹配的 Price
s 匹配 Price
s,在后一种情况下添加 Amount
。