0

enter image description here

I'm having a node relationship like above diagram

my Classes

@NodeEntity
public class User 
{


    @GraphId
    private Long id;

    @Property(name="name")
    private String name;


    @Relationship(type = "CAN_ACCESS", direction = Relationship.OUTGOING)
    private List<Library> libraries;


    // is this necessary ?????
    @Relationship(type = "CAN_ACCESS", direction = Relationship.OUTGOING)
    private List<Book> books;


    public User() 
    {

    }

    // getters
    // setters  
}


@NodeEntity
public class Library 
{
    @GraphId
    private Long id;

    @Property(name="name")
    private String name;


    @Relationship(type = "CONTAINS", direction = Relationship.OUTGOING)
    private List<Book> books;

    // is this necessary ?????
    @Relationship(type = "CAN_ACCESS", direction = Relationship.INCOMING)
    private List<User> users;


    public Library() 
    {

    }

    // getters
    // setters  
}

@NodeEntity
public class Book 
{
    @GraphId
    private Long id;

    @Property(name="name")
    private String name;

    // is this necessary ?????
    @Relationship(type = "CONTAINS", direction = Relationship.INCOMING)
    private Library library;

    // is this necessary ?????
    @Relationship(type = "CAN_ACCESS", direction = Relationship.INCOMING)
    private List<User> users;


    public Book() 
    {

    }

    // getters
    // setters  
}

I have User node Id = 21 and Library node Id = 32.I want to query Books that belongs to Library 32 but only User 21 can access.

Note - although User 21 "CAN_ACCESS" Library 32, that does not mean he "CAN_ACCESS" all Books "CONTAINS" in Library 32

My current approach in my service class is

@Autowired
private LibraryRepository libraryRepository;

@Autowired
private UserRepository userRepository;

@Autowired
private BookRepository bookRepository;

@Autowired
private Session session;


public void testGraph()
{
    Long userId = 21;
    Long libId = 32;
    int depth = 1;

    Library library = libraryRepository.findOne(32,depth);
    List<Book> books = library.getBooks();
    List<Book> userAccessibleBooks = getUserAccessibleBooks(books,userId);
}

public List<Book> getUserAccessibleBooks(List<Book> books,Long userId)
{
    // Loop over book list and get List<User> users;
    // check this user "CAN_ACCESS" the book
    // return accessible book list
}

I don't think this is the best approach. Assuming you have millions of Books in Library

Any solution ? or am i missing something in Spring data neo4j (Filters) ?

Summary

I want to get Library 32 with filtered Book List as children which User 21 "CAN_ACCESS"

Lakshitha Herath
  • 628
  • 2
  • 9
  • 18
  • Your approach seem good, because if having access to a library doesn't grant access to every book in it, you have to specify for each book if you have access or not. I recommend renaming each `CAN_ACCESS` relation ship tho, like `CAN_ACCESS_BOOK` and `CAN_ACCESS_LIBRARY` – Supamiu Mar 25 '16 at 09:53

1 Answers1

1

You want to use repository finder for this kinds of queries. You want to return List<Book> so this will go into BookRepository.

Easiest way is to define a cypher query:

MATCH (u:User), (l:Library)
WHERE 
ID(u) = {userId} AND ID(u) = {libraryId}
MATCH 
(u)-[:CAN_ACCESS]->(b:Book),
(l)-[:CONTAINS]-(b)
RETURN b

Using native graph ids is not really recommended, so if you introduce e.g. uuid the query might look like this:

MATCH 
(u:User {uuid:{userUuid}}),
(l:Library {uuid:{libraryUuid}}),
(u)-[:CAN_ACCESS]->(b:Book),
(l)-[:CONTAINS]-(b)
RETURN b

Then add a finder method with this query into BookRepository interface:

@Query("MATCH 
(u:User {uuid:{userUuid}}),
(l:Library {uuid:{libraryUuid}}),
(u)-[:CAN_ACCESS]->(b:Book),
(l)-[:CONTAINS]-(b)
RETURN b")
List<Book> findBooksByUserAndLibrary(@Param("userUuid") String userUuid, @Param("libraryUuid) String libraryUuid);
František Hartman
  • 14,436
  • 2
  • 40
  • 60