使用Cypher将多行收集到一列中

时间:2016-09-08 23:33:53

标签: neo4j cypher

我有一个存储在neo4j中的严重关联的数据模型。数据如下:

Component -> Part (only 1)
         \-> Fastener (only 1)

随后,任何带有标签Part或Fastener的节点都可以有任意数量的链接到其他节点(但永远不会回到组件)。

我要做的是返回所有组件的Part列,Fastener列,以及该Part的连接的一列(比如一个字典数组)以及该Fastener连接的一列。

目前我有一个非常基本的查询“工作”但产生同一组件的多行,其中一行包含唯一的零件或紧固件连接。查询是:

MATCH (c:Component)-[:MADE_WITH]->(p:Part), (c)-[:MADE_WITH]->(f:Fastener), (p)-[p_m:MATERIAL]->(p_m_unk), (f)-[f_m:MATERIAL]->(f_m_unk)
RETURN c.name, p, f, p_m_unk, p_m, f_m_unk, f_m

经过一些阅读后,似乎COLLECT功能将完成我需要的部分功能,但如果我这样做:

MATCH (c:Component)-[:MADE_WITH]->(p:Part), (c)-[:MADE_WITH]->(f:Fastener), (p)-[p_m:MATERIAL]->(p_m_unk), (f)-[f_m:MATERIAL]->(f_m_unk)
RETURN c.name, p, f, COLLECT([p_m_unk, p_m]), COLLECT([f_m_unk, f_m])

由于具有较少数据的列(p_m_unkf_m_unk)将具有重复的行,因此这并不是我想要的。

如何让此查询为包含所有部件c.name,紧固件p以及所有各自的第一级连接的每个f返回一行?

(我已经将标签的实际结构和名称更改为比我的用例更通用,但数据模型和查询仍然相同。)

3 个答案:

答案 0 :(得分:3)

您正走在正确的轨道上,我认为问题在于您在开始时尝试进行所有匹配,即生成笛卡尔积并最终在您的收藏中创建重复项。您将要分解您的匹配项,单独收集数据(因此每个步骤的输出是每个组件的一行)以避免使用笛卡尔积。

// you can still match against part and fastener together to start
MATCH (c:Component)-[:MADE_WITH]->(p:Part), (c)-[:MADE_WITH]->(f:Fastener) 
WITH c, p, f
// now match on part connections and collect
MATCH (p)-[:MATERIAL]->(p_m_unk)
WITH c, p, f, COLLECT(p_m_unk) as partConnections
// now match on fastener connections and collect
MATCH (f)-[:MATERIAL]->(f_m_unk)
// could do a return here if we wanted to
WITH c, p, f, partConnections, COLLECT(f_m_unk) as fastenerConnections
RETURN c.name, p, f, partConnections, fastenerConnections

答案 1 :(得分:1)

如果可以按@app.route('/active_jobs/new', methods=['POST']) def add_job(): ajobs = mongo.db.ajobs jobdate = request.json['jobdate']# date of job jobtime = request.json['jobtime']# time of job plant = request.json['plant']# plant for job po = request.json['po']# production order company = request.json['company']# client company name client = request.json['client']# person in charge jobaddress = request.json['jobaddress']#job address use = request.json['use']# concrete use in site m3 = request.json['m3']#job volume formula = request.json['formula']#job formula placement = request.json['placement']#type of placement badmix1 = request.json['badmix1']#batch admixture add-on badmix2 = request.json['badmix2']#batch admixture add-on badmix3 = request.json['badmix3']#batch admixture add-on confirmation = request.json['confirmation']#level of confirmation for job status = request.json['status']#job status ajob_id = ajobs.insert({ 'jobdate' : jobdate, 'jobtime' : jobtime, 'plant': plant, 'po' : po, 'company' : company, 'client' : client, 'jobaddress' : jobaddress, 'use' : use, 'm3' : m3, 'formula' : formula, 'placement' : placement, 'badmix1' : badmix1, 'badmix2' : badmix2, 'badmix3' : badmix3, 'confirmation' : confirmation, 'status' : status }) new_job = ajobs.find_one({'_id' : ajob_id}) output = ({ 'jobdate' : new_job['jobdate'], 'jobtime' : new_job['jobtime'],'plant': new_job['plant'], 'po': new_job['po'], 'company': new_job['company'], 'client': new_job['client'], 'jobaddress': new_job['jobaddress'], 'm3': new_job['m3'], 'use': new_job['use'], 'formula': new_job['formula'], 'placement': new_job['placement'], 'badmix1': new_job['badmix1'], 'badmix2': new_job['badmix2'], 'badmix3': new_job['badmix3'], 'confirmation': new_job['confirmation'],'status': new_job['status'] }) return jsonify({'verify new job': output}) 返回两行,Component一行,Part一则,则查询可以这样简单:

Fastener

该查询假定MATCH (c:Component)-[:MADE_WITH]->(pf)-[m:MATERIAL]->(unk) RETURN c.name, LABELS(pf)[0] AS label, pf, COLLECT({m:m, unk:unk}) AS materials; Part个节点没有其他标签。

以下是一个示例结果:

Fastener

但是,如果您真的是单行上每个╒══════╤════════╤═════════════╤══════════════════════════════╕ │c.name│label │pf │materials │ ╞══════╪════════╪═════════════╪══════════════════════════════╡ │Froomb│Fastener│{name: Batz} │[{m: {name: MFlidget}, unk: {n│ │ │ │ │ame: Flidget}}, {m: {name: MCo│ │ │ │ │rb}, unk: {name: Corb}}] │ ├──────┼────────┼─────────────┼──────────────────────────────┤ │Froomb│Part │{name: Bleet}│[{m: {name: MSignaft}, unk: {n│ │ │ │ │ame: Signaft}}, {m: {name: MTr│ │ │ │ │em}, unk: {name: Trem}}, {m: {│ │ │ │ │name: MMert}, unk: {name: Mert│ │ │ │ │}}] │ └──────┴────────┴─────────────┴──────────────────────────────┘ 的结果,则此查询将执行此操作:

Component

MATCH (c:Component)-[:MADE_WITH]->(pf)-[m:MATERIAL]->(unk) WITH c.name AS name, pf, COLLECT(m) AS ms, COLLECT(unk) AS unks ORDER BY LABELS(pf)[0] DESC WITH name, COLLECT({pf: pf, ms:ms, unks:unks}) AS data RETURN name, (data[0]).pf AS p, (data[1]).pf AS f, (data[0]).ms AS p_ms, (data[0]).unks AS p_m_unks, (data[1]).ms AS f_ms, (data[1]).unks AS f_m_unks; 子句按ORDER BY节点的标签按降序排序,以便在pf集合中data数据的索引为0并且Part数据的索引为。

以下是结果的样子(使用相同的样本数据):

Fastener

答案 2 :(得分:0)

您可以在DISTINCT函数调用中使用COLLECT修饰符。

RETURN c.name, p, f, COLLECT(DISTINCT [p_m_unk, p_m]), COLLECT(DISTINCT [f_m_unk, f_m])

这将删除更长的列表中的重复项。