Spring Data Neo4j:按LocalDate过滤不起作用

时间:2018-09-20 18:27:48

标签: java neo4j spring-data-neo4j

我的小型Neo4j运动场应用程序(基于Spring Boot 2,Spring Data Neo4j和嵌入式驱动程序)是一个小型的记笔记软件。用户可以按创建日期过滤其笔记。为了更好地了解Cypher,我使用SDN的@QueryNoteRepo.findByDay(day))编写了Cypher查询。

但是我无法进行过滤。我对LocalDate转换为地图(控制台输出的最后一行)感到困惑。在上一个查询(NoteRepo.findBySnoozeUntil(day)中,使用SDN的repo查询关键字),一切都很好,并且day转换为ISO 8601日期。

有人可以指出它的问题并进行修复吗?

Note.java

@NodeEntity
class Note {
    @Id
    @GeneratedValue
    private Long id;
    private String content;
    private LocalDateTime created;
    private LocalDate snoozedUntil;
    // constructors, getters, setters, ... omitted
}

NoteRepo.java

import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.Neo4jRepository;

import java.time.LocalDate;
import java.util.List;

interface NoteRepo extends Neo4jRepository<Note, Long> {
    // FIXME find all notes created on a specific day
    // currently returns an empty list
    @Query("MATCH (n: Note) WHERE date(datetime(n.created)) = {0} RETURN n")
    List<Note> findByDay(LocalDate day);

    List<Note> findBySnoozeUntil(LocalDate day);
}

App.java

package com.example.neo4jquerywithlocaldate;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.time.LocalDate;
import java.time.LocalDateTime;

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        var ctx = SpringApplication.run(App.class, args);
        var repo = ctx.getBean(NoteRepo.class);
        var tomorrow = LocalDate.now().plusDays(1);
        repo.save(new Note("learn neo4j", LocalDateTime.now(), tomorrow));

        var notesForTomorrow = repo.findBySnoozeUntil(tomorrow);
        System.out.println("notes snoozed until tomorrow = " + notesForTomorrow);

        var todaysNotes = repo.findByDay(LocalDate.now());
        System.out.println("today's notes = " + todaysNotes);
    }
}

Spring Boot应用程序的控制台输出(被截断为Neo4j查询和System.out.println)

UNWIND {rows} as row CREATE (n:`Note`) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, {type} as type with params {type=node, rows=[{nodeRef=-1, props={snoozeUntil=2018-09-21, created=2018-09-20T19:38:54.732260, content=learn neo4j}}]}

MATCH (n:`Note`) WHERE n.`snoozeUntil` = { `snoozeUntil_0` } WITH n RETURN n, ID(n) with params {snoozeUntil_0=2018-09-21}

< notes for tomorrow = [Note{id=0, content='learn neo4j', created=2018-09-20T19:38:54.732260}]

MATCH (n: Note) WHERE date(datetime(n.created)) = {0} RETURN n with params {0={year=2018, month=SEPTEMBER, monthValue=9, dayOfMonth=20, chronology={id=ISO, calendarType=iso8601}, dayOfWeek=THURSDAY, era=CE, dayOfYear=263, leapYear=false}}

< today's notes = []

复制项目:Spring Initializr Project

将此添加到build.gradle

ext['neo4j-ogm.version'] = '3.1.3'

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
    runtimeOnly 'org.neo4j:neo4j:3.4.7'
    runtimeOnly 'org.neo4j:neo4j-ogm-embedded-driver:3.1.3'
}

并添加上面的类。

1 个答案:

答案 0 :(得分:1)

目前,使用嵌入式驱动程序处理派生查询器(类似于List<Note> findBySnoozedUntil(LocalDate day);的查询器与用@Query注释的查询器)的处理方式不同。

嵌入式驱动程序当前将所有参数映射到字符串上。对于这两个,它无条件地使用Jacksons ObjectMapper的实例。

我们需要几个步骤来解决此问题。

  1. 教ObjectMapper使用合理的格式。这很容易,您已经启动了,因此请添加此启动程序compile('org.springframework.boot:spring-boot-starter-json'),它将带来许多有用的Jackson模块。如果您打算编写一个Web应用程序并且已经拥有spring-boot-starter-webspring-boot-starter-webflux,则可以省略JSON启动程序,这些模块将其引入。

  2. 在OGM的嵌入式Objectmapper中注册随附的Java 8 Jackson modules,并禁用写入日期作为时间戳,即在您的App.class中:

final ObjectMapper ogmObjectMapper = org.neo4j.ogm.config.ObjectMapperFactory.objectMapper();
ogmObjectMapper.registerModule(new JavaTimeModule());
ogmObjectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
  1. 由于嵌入式驱动程序使用此配置将值映射为String,因此您不得不修改查询:
@Query("MATCH (n: Note) WHERE date(datetime(n.created)) = date({0}) RETURN n")
List<Note> findByDay(LocalDate day);

相关的输出现在是

2018-09-24 10:50:53.313  INFO 2860 --- [           main] o.n.o.d.e.request.EmbeddedRequest        : Request: MATCH (n:`Note`) WHERE n.`snoozedUntil` = { `snoozedUntil_0` } WITH n RETURN n, ID(n) with params {snoozedUntil_0=2018-09-25}
notes snoozed until tomorrow = [com.example.demo.Note@2420e962]
2018-09-24 10:50:53.522  INFO 2860 --- [           main] o.n.o.d.e.request.EmbeddedRequest        : Request: MATCH (n: Note) WHERE date(datetime(n.created)) = date({0}) RETURN n with params {0=2018-09-24}
today's notes = [com.example.demo.Note@363d3958]

编辑:使用Bolt对外部数据库也可以看到相同的效果,解决方案目前是相同的。