简体   繁体   中英

Why multiple nodes are created in Neo4j by CREATE or MERGE query

I'm using Cypher to create some data in Neo4j . It's a pretty straight forward product model, with following elements

  1. Product (eg a mobile)
  2. Features (eg quick charge)
  3. Related products (eg tampered glass)
  4. Outlets (eg local store, related products are sold through outlets)

I have written some query to insert the data. What it tries to do is

  • Create a product
  • Create a feature set
  • Link product with feature [:HAS_FEATURES]
  • Create outlets x3
  • Create related product 1
  • Link product to related product [:HAS_RP], and related product to all outlets [:SOLD_THROUGH]
  • Create related product 2
  • Link it to product & outlets like above

Below is the actual query

//Product
CREATE (p:Product {name: 'Cool Mobile YX Plus',
  key: 'MOB0001',
  version: 'X.1'
}),

//Features
(f:Features {hasQuickCharge: true,
  isAvailable: true,
  hasVolte: false
})

MERGE (p) -[:HAS_FEATURES]-> (f)

//Outlets (:Product level lookup)
CREATE (o1:Outlet {productType: 'New', seller: 'National_Shops', prId: 'MOB0001'})
CREATE (o2:Outlet {productType: 'New', seller: 'Local_Shops', prId: 'MOB0001'})
CREATE (o3:Outlet {productType: 'New', seller: 'Online_Shops', prId: 'MOB0001'})

//Related products
CREATE (rps1:RPS {rpId: 'TGS1108',
  rpName: 'YX Plus Tampered Glass',
  price: 180.99
})
WITH rps1
MATCH (ol1:Outlet {productType: 'New', prId: 'MOB0001'})
MATCH (pr1:Product {key: 'MOB0001'})
MERGE (pr1) -[:HAS_RP {typeName: 'Child'}]-> (rps1)
MERGE (rps1) -[:SOLD_THROUGH]-> (ol1)

CREATE (rps2:RPS {rpId: 'CVR0204',
  rpName: 'YX Plus back cover',
  price: 299.00
})
WITH rps2
MATCH (ol2:Outlet {productType: 'New', prId: 'MOB0001'})
MATCH (pr2:Product {key: 'MOB0001'})
MERGE (pr2) -[:HAS_RP {typeName: 'ChargeFor'}]-> (rps2)
MERGE (rps2) -[:SOLD_THROUGH]-> (ol2)

Now the problem is, the second related product is created 3 times , where it was expected to be created only once, just like the first related product.

Can anyone please help me understand what I'm doing wrong? Also, any help in writing the query in better way would be great.

在此处输入图片说明

The issue is located here :

MATCH (ol1:Outlet {productType: 'New', prId: 'MOB0001'})

You created before 3 nodes that comply to the criteria of the MATCH :

CREATE (o1:Outlet {productType: 'New', seller: 'National_Shops', prId: 'MOB0001'}) CREATE (o2:Outlet {productType: 'New', seller: 'Local_Shops', prId: 'MOB0001'}) CREATE (o3:Outlet {productType: 'New', seller: 'Online_Shops', prId: 'MOB0001'})

So, MATCH (ol1:Outlet {productType: 'New', prId: 'MOB0001'}) will return 3 rows, and for each row, it will execute the next part of the query, 3 times this part :

MATCH (pr2:Product {key: 'MOB0001'})
MERGE (pr2) -[:HAS_RP {typeName: 'ChargeFor'}]-> (rps2)
MERGE (rps2) -[:SOLD_THROUGH]-> (ol2)

Just writing an extension to what @Christophe and @InverseFalcon already answered/commented. As explained in resetting query cardinality , this issue was caused by executing CREATE multiple times.

Queries execute per row. So, when a MATCH is followed by a CREATE , based on the match results, the CREATE statement might get executed multiple times and create multiple copies of data (unless unique/node key constraints are there) which was originally intended to be created only once.

MERGE can help with the issues since it'll not create multiple copies, but the MERGE is still executed multiple times.

This can be handled by "resetting query cardinality" using WITH DISTINCT . Below shows an updated query that solves the issue, and the figure shows the new results.

//Related products
CREATE (rps1:RPS {rpId: 'TGS1108',
  rpName: 'YX Plus Tampered Glass',
  price: 180.99
})
WITH rps1
MATCH (ol1:Outlet {productType: 'New', prId: 'MOB0001'}) //3 match
MATCH (pr1:Product {key: 'MOB0001'})
MERGE (pr1) -[:HAS_RP {typeName: 'Child'}]-> (rps1)
MERGE (rps1) -[:SOLD_THROUGH]-> (ol1)

//next part of query will execute 3 times

//reset cardinality back to 1 with WITH DISTINCT
WITH DISTINCT 1 AS ResetCardinality
CREATE (rps2:RPS {rpId: 'CVR0204',
  rpName: 'YX Plus back cover',
  price: 299.00
}) //now CREATE & following executes only once
WITH rps2
MATCH (ol2:Outlet {productType: 'New', prId: 'MOB0001'})
MATCH (pr2:Product {key: 'MOB0001'})
MERGE (pr2) -[:HAS_RP {typeName: 'ChargeFor'}]-> (rps2)
MERGE (rps2) -[:SOLD_THROUGH]-> (ol2)

在此处输入图片说明

Since I'm new to this, if someone can show how the whole situation can be handled better with better written queries, that'll help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM