Spring Data Neo4j 7.1.2 - relationships only return empty sets

I'm using Spring 3.1.1 with SDN 7.1.2

I have the "Book" class below as a node. The other classes (for example the "Author" class), are also declared as nodes and have the complementing relationship declarations. There are no properties on the relationships.

In the Author class the following is declared:

@Relationship(type = "writtenBy", direction = INCOMING)     
private Set<Book> writtenBy = Collections.emptySet();

However, when I use a query to return a Book Node, and using the Getter (for example on "GetAuthors"), only an empty set is returned. I'm using Lombok and the Getters and Setters seem to be included correctly.

When I check the database with a browser, the relationship is there. Please also see an example from my "BookRepository" interface below:

@Repository
public interface BookRepository extends Neo4jRepository<Book, String> {

    Optional<Book> findOneByTitle(String title);

    boolean existsByTitle(String title);

    @Query("MATCH (book:Book) WHERE book.title = $title RETURN book")
    Book findABookManual(@Param("title") String title);

The "findOneByTitle" method is not working properly (it seems to go into a loop there and I don't know why - I have another thread for that). When I use the Manual Query above, the right node is returned pretty fast, however, the sets of the relationships are always empty sets, even when there are relationships in the database. I read that Lombok might not include "toString" methods automatically for fields not in the constructor, so I did the "ToString.Include", however, it does not work, no matter if it's there or not.

As a Book shall only have one Author node, I also tried a relationship declared on a single "Author" object, that just leads to a "null" returned.

import lombok.*;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Property;
import org.springframework.data.neo4j.core.schema.Relationship;

import java.util.*;

import static org.springframework.data.neo4j.core.schema.Relationship.Direction.INCOMING;
import static org.springframework.data.neo4j.core.schema.Relationship.Direction.OUTGOING;


@Data
@NoArgsConstructor
@ToString
@Node("Book")

public class Book {

    @Id
    private String title;
    @Property("characters")
    private List<String>characters;
    @Property("genres")
    private List<String> genres;
    @Property("description")
    private String description;
    @Property("bookFormat")
    private String bookFormat;
    @Property("loan")
    private boolean loan;

    @ToString.Include
    @Relationship(type = "published", direction = INCOMING)
    private Set<Publisher> publishers = Collections.emptySet();

    @ToString.Include
    @Relationship(type = "hasFormat", direction = OUTGOING)
    private Set<BookFormat> bookFormats = Collections.emptySet();

    @ToString.Include
    @Relationship(type = "writtenBy", direction = OUTGOING)
    private Set<Author> authors = Collections.emptySet();

    @ToString.Include
    @Relationship(type = "publishedIn", direction = OUTGOING)
    private Set<PublishDate> publishDates = Collections.emptySet();

    @ToString.Include
    @Relationship(type = "hasBorrowed", direction = INCOMING)
    private Set<LibraryUser> Borrowers = Collections.emptySet();



    public Book (String title, List<String> characters, List<String> genres, String description, String bookFormat, boolean loan) {
        this.title = title;
        this.characters = characters;
        this.genres = genres;
        this.description = description;
        this.bookFormat = bookFormat;
        this.loan = loan;

    }

Collections.emptySet() is an immutable type-safe collection. You don't want to use that if you intend on adding elements. Further, being a Collection it wouldn't have the extended features of a List even if you could add to it.

I have not set my related entities with an initialized list. Try the following instead:

private Set<LibraryUser> Borrowers

Thanks for the quick answer. I forgot to write into the first post that I already tried it with a normal Set initialization, like:

private Set<LibraryUser> Borrowers = new HashSet<>

I now tried it with

private Set<LibraryUser> Borrowers

unfortunately it still does not work. Only empty sets returned

What version of spring are you using?

I'm on Spring 3.1.1 and 7.1.2 SDN

But as I solved the problem with the infinite loops at least partly (thanks for your answer there), I recognized that as soon as I use the internal methods (like findByID and FindAll), the Sets are populated correctly. Only when I use custom Cypher queries that return a Node or a list of nodes, the sets are empty. I think that might be a mapping error. Do you know how do to do a custom query that the relationships are also returned? I have to write some more complex queries, so I think always falling back to the built in method to return a single node might be quite performance intensive.

Warning, I am a novice with Neo4j SDN. I used it the first time for a new springboot application I am building. I have used the java driver extensively for my other springboot applications because I was calling custom procedures I built. In this case I just needed CRUD operations on my entities.

Your observation makes sense. When you create a custom query, you need to provide the results so SDN can hydrate your domain entity. In your example you are only returning a Book, so your result will only have the Book properties and not the related entities.

If you want to include all the related entities, try the following:

   @Query("MATCH (book:Book) WHERE book.title = $title MATCH (book)-[r]-(m) RETURN book, collect(r) as rel, collect(m) as nodes")
    Book findABookManual(@Param("title") String title);

If it works, it will only hydrate your domain entity to one level. You would have to build out deeper levels if you want. I believe all the provided methods do this recursively.

https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/#custom-queries

That seem to work, however, with all my relationships that's quite a mess. Perhaps I have to think about whether all of this info have to be in separate nodes. I'm a newbie to Neo4j, is there a noteable performance gain if (for example I want to look for all the books published in the year 2000) a property is just defined in the node itself or as a separate node? I want to do a recommendation system, and I don't think the year of publication is really relevant for that (the same might be true for the name of the Publisher)

addition - it's a mess because your query (match all Relations of a Book) unfortunately does not work. You have to match all 5 relations with the name of the relation, collect and return them. That's quite a lot of boilerplate, in the end it might make more sense here to collect only the book titles. As they are unique, you can then loop through the collection of titles and use the (now working) findByID function on each

When you load a book to review, do you need more than the first level? If you use the given methods in the repository or define your own using the naming convention, neo4j SDN will get the entire domain entity at all levels. It recursively walks the graph from the root of the domain entity.

I think your issue with using the provided find methods is loops in the data. SDN is intended to manage domain entities. They can contain be complex hierarchies of data, but the are isolated. Your data seems to be a network of books and other entities all connected.

Maybe SDN is not the tool you need for your case. Remember, if you use a custom query and only read in a book and it’s immediate related nodes, make some changes and then save with the repository method, all the relationships to entities you did not load will be deleted.

Maybe SDN repositories are not the correct tool for your case. I had similar data in one application I wrote. I wrote my own repository methods using the Java driver, because I had to be able to add/remove a single entries to a network of connected entries.

Hi, I am encountering the same issue and I wonder if you have already solved it or have anything enlightening?

Can’t you post your code and/or explain your specific issue you are having so we can help?