Question

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?

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top