cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

Adding to a list with Spring Data Neo4j with Kotlin

wayne
Node Clone

Hello one and all, in a departure from my normal form, the code here seems to work; but I am just looking for some counsel to perhaps add a little more elegance.

org.springframework.data:spring-data-neo4j:6.0.5
kotlin 1.4.30

I lead an active life and so I have decided to keep a record of it.

So I have a diary

@Node
data class Diary constructor(@Id @GeneratedValue val id: Long? = null, val name: String, @Relationship(type = "DIARY_TO_ENTRY") val entriesList: List<Entry>)

and an Entry

@Node
data class Entry constructor(@Id @GeneratedValue val id: Long? = null, val localDate: LocalDate, val activity: String)

I have also started to add a few items into my diary

@SpringBootApplication
class DogyearsApplication {
    fun <T : Any> Optional<T>.asNonNullable(): T = this.orElseThrow()

    @Bean
    fun init(diaryRepository: DiaryRepository, entryRepository: EntryRepository): CommandLineRunner {
        return CommandLineRunner {
            val ld_2000Jan01: LocalDate = LocalDate.of(2000, Month.JANUARY, 1)
            val ld_2000Jan02: LocalDate = LocalDate.of(2000, Month.JANUARY, 2)
            val ld_2000Jan03: LocalDate = LocalDate.of(2000, Month.JANUARY, 3)
            val barkAtMailCarrier = "bark at mail carrier"
            val chaseSquirrel = "chase squirrel"
            val hideFromCat = "hide from cat"
            val entryJan01BarkAtMailCarrier = Entry(localDate = ld_2000Jan01, activity = barkAtMailCarrier)
            val entryJan01ChaseSquirrel = Entry(localDate = ld_2000Jan01, activity = chaseSquirrel)
            val entryJan02BarkAtMailCarrier = Entry(localDate = ld_2000Jan02, activity = barkAtMailCarrier)
            val entryJan02HideFromCat = Entry(localDate = ld_2000Jan02, activity = hideFromCat)
            
            diaryRepository.deleteAll()
            entryRepository.deleteAll()
            val diary = Diary(
                name="Rover",
                entriesList = listOf<Entry>
                    (entryJan01BarkAtMailCarrier, entryJan01ChaseSquirrel, entryJan02BarkAtMailCarrier,
                    entryJan02HideFromCat)
            )
            val savedDiary = diaryRepository.save<Diary>(diary)
            val diaryId = savedDiary.id

Now, if I wished to add further entries

            val entryJan03BarkAtMailCarrier = Entry(localDate = ld_2000Jan03, activity = barkAtMailCarrier)
            val entryJan03ChaseSquirrel = Entry(localDate = ld_2000Jan03, activity = chaseSquirrel)

I think there would be two ways to skin a cat, if you forgive my anti-feline sentiments.
Either I could read the whole diary into the Kotlin code, add an entry to the list and then save it again

            val readDiary = diaryRepository.findById(diaryId!!).asNonNullable()
            val extendedDiary = readDiary.copy(entriesList = readDiary.entriesList.plus(entryJan03BarkAtMailCarrier))
            diaryRepository.save<Diary>(extendedDiary)

or I could save the entry and call a specific custom query to add a relationship between the diary and the entry

            val savedEntry= entryRepository.save(entryJan03ChaseSquirrel)
            diaryRepository.addEntryToDiary(diaryId = diaryId, entryId = savedEntry.id!!)
@Repository
interface DiaryRepository : Neo4jRepository<Diary, Long> {
    @Query(
        value = "MATCH (d:Diary) " +
                "WHERE id(d)=\$diaryId " +
                "WITH d " +
                "MATCH (e:Entry) " +
                "WHERE id(e)=\$entryId " +
                "CREATE (d)-[:DIARY_TO_ENTRY]->(e) "
    )
    fun addEntryToDiary(
        @Param("diaryId") diaryId: Long, @Param("entryId") entryId: Long
    )
}

Even though my lifespan is somewhat shorter than that of my human companions, I would imagine that the latter strategy would be more efficient, as the diary got longer.

So, is there an alternative strategy here that I have not considered, either some spring data approach or a more effective custom cypher query ?

Any ideas gratefully accepted.

1 ACCEPTED SOLUTION

+1 to the custom query, this will be more efficient as entries grow in size.

View solution in original post

2 REPLIES 2

+1 to the custom query, this will be more efficient as entries grow in size.

Thanks for the feedback - I will stay with this approach then.