GraphGists

引言

这个周六下午的“沙发工作坊”的想法源于一个常见的情况,即一群人为一个聚会各自带来了食物补给。

然后就到了每个人必须为他/她所欠的钱互相支付的时候(A欠B €€€,B欠C €€€,等等)。

参与的人越多,就越有挑战性,有时会导致一些令人困惑的情况。我过去常常使用电子表格来解决这个问题,然后就出现了图数据库和Neo4j

设置

// 1. Initializing the Database
CREATE
(gaelle:Person {name: "Gaëlle"}),
(gregory:Person {name: "Gregory"}),
(mathilde:Person {name: "Mathilde"}),
(michel:Person {name: "Michel"}),
(yann:Person {name: "Yann"}),
(gaelle)-[:SPENT {amount: 100}]->(gaelle),
(gregory)-[:SPENT {amount: 35}]->(gregory),
(mathilde)-[:SPENT {amount: 67}]->(mathilde),
(michel)-[:SPENT {amount: 0}]->(michel),
(yann)-[:SPENT {amount: 85}]->(yann);

// 2. Adding the Debt Relationship
MATCH (p:Person)
WITH toFloat(count(p)) AS GuestsCount
MATCH (s:Person)
MATCH (t:Person)
MATCH (s)-[r:SPENT]-(s)
WHERE s <> t
AND r.amount <> 0
CREATE (t)-[:OWES_TO {amount: round(r.amount / GuestsCount * 100) / 100}]->(s);

// 3. Simplifying Mutual Debts
MATCH (s)-[r1:OWES_TO]->(t)
MATCH (t)-[r2:OWES_TO]->(s)
WHERE r1.amount - r2.amount > 0
// Create a new merged transaction...
CREATE (s)-[:OWES_TO {amount: round((r1.amount - r2.amount) * 100) / 100}]->(t)
// ...Then delete the previous ones
DELETE r1
DELETE r2;

问题

假设我们共有个人来参加我们的聚会。他们的费用是

MATCH (n)-[r:SPENT]-(n)
RETURN n.name as Person, r.amount AS Expense
ORDER BY Person;

初始化数据库

以下Cypher查询将创建人员(节点)及其费用(使用自关系)

CREATE
(gaelle:Person {name: "Gaëlle"}),
(gregory:Person {name: "Gregory"}),
(mathilde:Person {name: "Mathilde"}),
(michel:Person {name: "Michel"}),
(yann:Person {name: "Yann"}),
(gaelle)-[:SPENT {amount: 100}]->(gaelle),
(gregory)-[:SPENT {amount: 35}]->(gregory),
(mathilde)-[:SPENT {amount: 67}]->(mathilde),
(michel)-[:SPENT {amount: 0}]->(michel),
(yann)-[:SPENT {amount: 85}]->(yann);

注意:费用可以存储为人的一项属性。之所以更倾向于使用关系,是因为费用表示一个动作(用动词描述),而不是人的一个特征。

01 expenses
MATCH (n)-[r:SPENT]-(m) RETURN *;

添加债务关系

以下Cypher查询将在两个人之间添加一个关系,以指示第一个人欠第二个人的金额。

MATCH (p:Person)
WITH toFloat(count(p)) AS GuestsCount
MATCH (s:Person)
MATCH (t:Person)
MATCH (s)-[r:SPENT]-(s)
WHERE s <> t
AND r.amount <> 0
CREATE (t)-[:OWES_TO {amount: round(r.amount / GuestsCount * 100) / 100}]->(s);
02 debts

简化相互债务

就像在现实生活中一样,如果两个人互相欠钱,我们将这两笔交易合并为一笔。

这可以通过以下Cypher查询完成

MATCH (s)-[r1:OWES_TO]->(t)
MATCH (t)-[r2:OWES_TO]->(s)
WHERE r1.amount - r2.amount > 0
// Create a new merged transaction...
CREATE (s)-[:OWES_TO {amount: round((r1.amount - r2.amount) * 100) / 100}]->(t)
// ...Then delete the previous ones
DELETE r1
DELETE r2;

输出报告

Set 6 properties, deleted 12 relationships, created 6 relationships.
03 one transaction
MATCH (n)-[r]-(m) RETURN *;

获取账单

我们最后的Cypher查询总结了每个人的债务

MATCH ()-[r:OWES_TO]->()
WITH
    startNode(r).name AS Debitor,
    endNode(r).name AS Creditor,
    r.amount AS Amount
RETURN Debitor, Amount, Creditor
ORDER BY Debitor, Amount;

结论

只需修改第一个查询即可适用于您自己的情况。

祝您聚会愉快! :-)


创建者:Michel CARADEC - LinkedIn

© . All rights reserved.