I have a set of PlayStation Network games and a set of game text localizations (game title, game description, etc). I want to relate each game to a respective locale ("en", "fr", "de" for instance), but I'm unsure of the correct approach or if this is the right use of Cypher's FOREACH clause. I'm using Neo4jClient to add/update games and add/update respective locales. Here is the code I have so far:
client.Cypher
.ForEach("(game in {PSNGames} | MERGE (g:PSNGame {NPCOMMID : game.NPCOMMID}) SET g = game)")
.WithParams(new
{
PSNGames = games.ToList()
})
.ExecuteWithoutResults();
client.Cypher
.ForEach("(localized in {PSNGamesLocalized} | MERGE (l:PSNGameLocalized {NPCOMMID : localized.NPCOMMID}) SET l = localized)")
.WithParams(new
{
PSNGamesLocalized = localizedGames.ToList()
})
.ExecuteWithoutResults();
My thought is to do another ForEach
call and MERGE
the relationship:
MATCH (g:PSNGame) WITH COLLECT(g) AS games
FOREACH (game IN games | MERGE game-[:LOCALE]->(l:PSNGameLocalized {NPCOMMID : game.NPCOMMID}))
However, this creates new PSNGameLocalized labels, nodes and properties:
Added 93 labels, created 93 nodes, set 93 properties, created 93 relationships, returned 0 rows in 326 ms
I had been manually creating each node and adding/updating each relationship and this was proving to be very slow. I like the idea of bulk transactions for speeding up data importing. How do I go about adding/updating relationships while taking advantage of FOREACH
?
After some more thought on solving the problem, I came up with the following:
client.Cypher
.Match("(p:PSNProfile {PSNId : {profile}.PSNId})")
.ForEach(@"(game in {PSNGames} |
MERGE p-[:PLAYS {LastPlayed : game.LastUpdated}]->(g:PSNGame {NPCOMMID : game.NPCOMMID})-[:LOCALE]->(l:PSNGameLocalized {NPCOMMID : game.NPCOMMID})
SET g = game,
l = { NPCOMMID : game.NPCOMMID,
TitleName : game.TitleName,
TitleDetail : game.TitleDetail,
Locale : {locale}
})")
.WithParams(new
{
PSNGames = games.ToList(),
locale = locale,
profile = profile
})
.ExecuteWithoutResults();
The key behind this is to let Cypher take care of the foreach loops. I no longer have to do a foreach loop on the C# side. By passing parameters, I can dynamically create/update nodes and relationships by taking advantage of the MERGE
command. This approach is several magnitudes faster than my previous approach. I hope this can help someone else with a similar problem.