|
|
@ -389,4 +389,89 @@ class OperationService: |
|
|
result = self.db.execute_write_and_return(cypher, {"id": rel_id}) |
|
|
result = self.db.execute_write_and_return(cypher, {"id": rel_id}) |
|
|
return {"success": True, "msg": "删除成功"} if result else {"success": False, "msg": "关系不存在"} |
|
|
return {"success": True, "msg": "删除成功"} if result else {"success": False, "msg": "关系不存在"} |
|
|
except Exception as e: |
|
|
except Exception as e: |
|
|
return {"success": False, "msg": f"删除失败: {str(e)}"} |
|
|
return {"success": False, "msg": f"删除失败: {str(e)}"} |
|
|
|
|
|
|
|
|
|
|
|
# --- 7. 导出功能 --- |
|
|
|
|
|
def export_nodes_to_json(self, label=None, name=None): |
|
|
|
|
|
""" |
|
|
|
|
|
按照条件导出节点,确保包含 identity, elementId, labels, properties 等所有原始字段 |
|
|
|
|
|
""" |
|
|
|
|
|
try: |
|
|
|
|
|
conditions = [] |
|
|
|
|
|
params = {} |
|
|
|
|
|
|
|
|
|
|
|
# 构建过滤条件(复用查询逻辑,但去掉分页) |
|
|
|
|
|
if name: |
|
|
|
|
|
params["name"] = unquote(str(name)).strip() |
|
|
|
|
|
conditions.append("n.name CONTAINS $name") |
|
|
|
|
|
|
|
|
|
|
|
lb_clause = "" |
|
|
|
|
|
if label and label not in ["全部", ""]: |
|
|
|
|
|
# 为了保证原生对象的完整性,这里直接 MATCH 标签 |
|
|
|
|
|
lb_clause = f":`{label}`" |
|
|
|
|
|
|
|
|
|
|
|
where_clause = "WHERE " + " AND ".join(conditions) if conditions else "" |
|
|
|
|
|
|
|
|
|
|
|
# 注意:这里 RETURN n,返回的是整个节点对象 |
|
|
|
|
|
cypher = f"MATCH (n{lb_clause}) {where_clause} RETURN n" |
|
|
|
|
|
|
|
|
|
|
|
raw_data = self.db.execute_read(cypher, params) |
|
|
|
|
|
|
|
|
|
|
|
export_items = [] |
|
|
|
|
|
for row in raw_data: |
|
|
|
|
|
node = row['n'] |
|
|
|
|
|
# 核心逻辑:提取 Neo4j 节点对象的所有原生属性 |
|
|
|
|
|
node_data = { |
|
|
|
|
|
"identity": node.id, # 对应你截图中的 identity (旧版 ID) |
|
|
|
|
|
"elementId": node.element_id, # 对应你截图中的 elementId (新版 ID) |
|
|
|
|
|
"labels": list(node.labels), |
|
|
|
|
|
"properties": dict(node.items()) |
|
|
|
|
|
} |
|
|
|
|
|
export_items.append(node_data) |
|
|
|
|
|
|
|
|
|
|
|
return {"success": True, "data": export_items} |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
traceback.print_exc() |
|
|
|
|
|
return {"success": False, "msg": f"导出节点失败: {str(e)}"} |
|
|
|
|
|
|
|
|
|
|
|
def export_relationships_to_json(self, source=None, target=None, rel_type=None): |
|
|
|
|
|
""" |
|
|
|
|
|
按照条件导出关系,确保包含起始/结束节点信息及完整属性 |
|
|
|
|
|
""" |
|
|
|
|
|
try: |
|
|
|
|
|
conditions = [] |
|
|
|
|
|
params = {} |
|
|
|
|
|
if source: |
|
|
|
|
|
params["source"] = unquote(str(source)).strip() |
|
|
|
|
|
conditions.append("a.name CONTAINS $source") |
|
|
|
|
|
if target: |
|
|
|
|
|
params["target"] = unquote(str(target)).strip() |
|
|
|
|
|
conditions.append("b.name CONTAINS $target") |
|
|
|
|
|
if rel_type and rel_type not in ["全部", ""]: |
|
|
|
|
|
conditions.append(f"type(r) = $rel_type") |
|
|
|
|
|
params["rel_type"] = rel_type |
|
|
|
|
|
|
|
|
|
|
|
where_clause = "WHERE " + " AND ".join(conditions) if conditions else "" |
|
|
|
|
|
|
|
|
|
|
|
# 返回关系对象 r 以及起止节点的 elementId 以便追溯 |
|
|
|
|
|
cypher = f"MATCH (a)-[r]->(b) {where_clause} RETURN r, elementId(a) as startNode, elementId(b) as endNode" |
|
|
|
|
|
|
|
|
|
|
|
raw_data = self.db.execute_read(cypher, params) |
|
|
|
|
|
|
|
|
|
|
|
export_items = [] |
|
|
|
|
|
for row in raw_data: |
|
|
|
|
|
rel = row['r'] |
|
|
|
|
|
rel_data = { |
|
|
|
|
|
"identity": rel.id, |
|
|
|
|
|
"elementId": rel.element_id, |
|
|
|
|
|
"type": rel.type, |
|
|
|
|
|
"startNodeElementId": row['startNode'], |
|
|
|
|
|
"endNodeElementId": row['endNode'], |
|
|
|
|
|
"properties": dict(rel.items()) |
|
|
|
|
|
} |
|
|
|
|
|
export_items.append(rel_data) |
|
|
|
|
|
|
|
|
|
|
|
return {"success": True, "data": export_items} |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
traceback.print_exc() |
|
|
|
|
|
return {"success": False, "msg": f"导出关系失败: {str(e)}"} |