The following query should return the account sorted by the number "followers" in desc order, with a limit.
It takes 2 variables as params (maxCount and limit). MaxCount refers to a numbers of followers. so if maxCount is 100, then return only those accounts that have followers less than 100.
If I run this query in a Spring Data Neo4j App. It seems to ignore maxCount constraint e.g. If I set maxCount equal to 2 and have account1 with 3 followers and account2 with 1 follower. It seems to incorrectly return both accounts when it should only return account2 which has only 1 follower.
Query
@Query("MATCH (a:Account)<-[:follows]-(b:Account) WITH a, COLLECT(b)
AS bs WHERE SIZE(bs) < {0} RETURN a ORDER BY SIZE(bs) DESC LIMIT {1}")
List<Account> findCappedSortedAccountByFollowers(int maxCount, int resultSize);
It works if I enter it directly into Neo4j Console
Perhaps this is Spring Data Bug?
SDN Version: 4.1.3.RELEASE
OGM Embedded Driver Version: 2.0.5
Small App to demonstrate problem available here
Here is your code updated to work with the new versions. Both tests pass. I've rewritten your test and model to be more in line with our documentation and examples. Remember that the OGM can persist by reachability. Hope this helps you get past your issue. I've explained how to write Transactional type tests with Spring Data here: https://stackoverflow.com/a/39887536/2271422.
build.gradle
:
dependencies {
compile "ch.qos.logback:logback-classic:1.1.7"
compile "org.springframework.data:spring-data-neo4j:4.2.0.BUILD-SNAPSHOT"
compile "org.springframework:spring-test:4.3.3.RELEASE"
compile "org.neo4j:neo4j-ogm-embedded-driver:2.1.0-SNAPSHOT"
testCompile "junit:junit:4.12"
}
src/main/java
com.neo4j.relation.config
:
@Configuration
@EnableNeo4jRepositories("com.neo4j.relation.repository")
@EnableTransactionManagement
public class EmbeddedNeo4JConfig {
@Bean
public SessionFactory sessionFactory() {
return new SessionFactory("com.neo4j.relation.model");
}
@Bean
public PlatformTransactionManager transactionManager() {
return new Neo4jTransactionManager(sessionFactory());
}
}
src/main/java
com.neo4j.relation.model
:
@NodeEntity
public class Account {
@GraphId
private Long id;
private String name;
@Relationship(type = "FOLLOWS",
direction = Relationship.OUTGOING)
private Set<Account> following = new HashSet<Account>();
@Relationship(type = "FOLLOWS",
direction = Relationship.INCOMING)
private Set<Account> followers = new HashSet<Account>();
private Account() {
}
private Account(String name) {
this.name = name;
}
public static Account newAccountInstance(String name) {
return new Account(name);
}
//Accessors
public Long getId() {
return id;
}
public Set<Account> getFollowers() {
return followers;
}
public String getName() {
return name;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Id: ").append(getId()).append(", ");
sb.append("Name: ").append(getName()).append(", ");
return sb.toString();
}
}
src/main/java
com.neo4j.relation.repository
:
public interface AccountRepository extends GraphRepository<Account> {
@Query("MATCH (a:Account)<-[:FOLLOWS]-(b:Account) WITH a, COLLECT(b) AS bs ORDER BY SIZE(bs) DESC RETURN a LIMIT {0}")
List<Account> findSortedAccountByFollowers(int maxSize);
@Query("MATCH (a:Account)<-[:FOLLOWS]-(b:Account) WITH a, COLLECT(b) AS bs WHERE SIZE(bs) <= {0} RETURN a ORDER BY SIZE(bs) DESC LIMIT {1}")
List<Account> findCappedSortedAccountByFollowers(int maxCount, int resultSize);
}
src/test/resources
logback.xml
:
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %5p %40.40c:%4L - %m%n</pattern>
</encoder>
</appender>
<logger name="org.neo4j.ogm" level="debug" />
<logger name="org.springframework" level="warn" />
<logger name="org.springframework.data.neo4j" level="debug" />
<root level="debug">
<appender-ref ref="console" />
</root>
</configuration>
src/test/resources
com.neo4j.test
:
@ContextConfiguration(classes = {EmbeddedNeo4JConfig.class})
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
public class AccountTester {
@Autowired
AccountRepository accountRepository;
@Test
public void testFindSortedAccountByFollowers() {
Account account = Account.newAccountInstance("James Martin");
Account account2 = Account.newAccountInstance("Steve Owen");
Account account3 = Account.newAccountInstance("Bill Gates");
Account account4 = Account.newAccountInstance("Steve Jobs");
account.getFollowers().add(account2);
accountRepository.save(account);
accountRepository.save(account3);
accountRepository.save(account4);
assertNotNull(account.getId());
final Iterable<Account> all = accountRepository.findAll();
assertEquals(4, IteratorUtils.size(all.iterator()));
List<Account> accounts = accountRepository.findSortedAccountByFollowers(10);
int size = accounts.size();
assertEquals(1, size);
assertEquals(account, accounts.get(0));
}
@Test
public void testCappedSortAccountByFollowerCount() {
Account account = Account.newAccountInstance("Steve Martin");
Account account2 = Account.newAccountInstance("Steve Owen");
Account account3 = Account.newAccountInstance("Bill Gates");
Account account4 = Account.newAccountInstance("Steve Jobs");
account.getFollowers().add(account2);
account.getFollowers().add(account3);
account.getFollowers().add(account4);
account4.getFollowers().add(account3);
accountRepository.save(account);
List<Account> accounts = accountRepository.findCappedSortedAccountByFollowers(2, 10);
int size = accounts.size();
assertEquals(1, size);
assertEquals(account4, accounts.get(0));
}
}