我正在使用 Neo4j 构建一个论坛。在我的论坛中,有些帖子属于某些类别,并且可能包含多个标签。当我从数据库中获取线程时,我希望结果以以下形式返回:
{
id,
title,
creationDateTime,
likeCount,
postCount,
viewCount,
tags: []
}
为了实现这一目标,我在查询中使用了 COLLECT{} 表达式。以下是我的疑问:
@Query("CREATE (accountType:AccountType {id: randomUUID(), name: $name, authorities: $authorities}) RETURN accountType")
public AccountType createAccountType(String name, List<AccountTypeEnum> authorities);
@Query("MERGE (accountType:AccountType {name: 'NORMAL_USER'}) " +
"CREATE (newAccount:ForumAccount:NotificationTrigger {id: randomUUID(), userName: $userName, password: $password, email: $email, joinDate: date(), type: 'account'}) " +
"MERGE (newAccount)-[:BELONGS_TO_ACCOUNT_TYPE]->(accountType) " +
"RETURN newAccount")
public ForumAccount createNewAccount(String userName, String password, String email);
@Query("CREATE (category:Category {id: randomUUID(), categoryName: $categoryName}) RETURN category.id AS id, category.categoryName AS categoryName")
public Category createCategory(String categoryName);
@Query("CREATE (tag:Tag {id: randomUUID(), tagName: $tagName}) RETURN tag")
public Tag createNewTag(String tagName);
@Query("MATCH (user:ForumAccount {id: $accountId}) " +
"MATCH (category:Category {id: $categoryId}) " +
"MERGE (category)-[:CONTAINS_THREAD]->(thread: Thread {id: randomUUID(), title: $title, creationDateTime: localdatetime(), toxicStatus: $toxicStatus, resolveStatus: false}) " +
"MERGE (user)-[:CREATES]->(thread) " +
"MERGE (thread)-[:CREATED_BY]->(user) " +
"WITH thread, COALESCE($tags, []) AS tags " +
"FOREACH (tagData IN tags | " +
" MERGE (tag:Tag {id: tagData.__id__, tagName: tagData.__properties__.tagName}) " +
" MERGE (thread)-[:CONTAINS_TAGS]->(tag) " +
" MERGE (tag)-[:BELONGS_TO]->(thread)) " +
"RETURN thread")
public Thread addNewThread(UUID accountId, String title, String toxicStatus, Set<Tag> tags, UUID categoryId);
@Query("MATCH (author:ForumAccount {id: $accountId})-[:CREATES]->(thread:Thread {toxicStatus: 'NOT_TOXIC'}) " +
"RETURN thread.id AS id, thread.title AS title, thread.resolveStatus as resolveStatus, thread.creationDateTime AS creationDateTime, 0 AS likeCount, 0 AS postCount, 0 AS viewCount, " +
"COLLECT {OPTIONAL MATCH (thread)-[:CONTAINS_TAGS]->(tag:Tag) RETURN tag.tagName} AS tags " +
"ORDER BY thread.creationDateTime " +
"SKIP $offset LIMIT $limit"
)
public List<StandardThreadResponseDTO> getThreadsByAccountId(UUID accountId, int offset, int limit);
以下是我的StandardThreadResponseDTO
package com.gymhub.gymhub.dto.ResponseDTO.ThreadResponseDTO;
import com.gymhub.gymhub.domain.Tag;
import com.gymhub.gymhub.dto.ResponseDTO.TagResponseDTO;
import lombok.*;
import org.springframework.data.neo4j.core.schema.Node;
import java.time.LocalDateTime;
import java.util.*;
@Getter
@Setter
@NoArgsConstructor
public class StandardThreadResponseDTO {
private UUID id;
private String title;
private LocalDateTime creationDateTime;
private boolean resolveStatus;
@Setter
private int likeCount;
@Setter
private int viewCount;
@Setter
private int postCount;
private Set<String> tags = new HashSet<>();
public StandardThreadResponseDTO(UUID id, String title, LocalDateTime creationDateTime, boolean resolveStatus, Set<String> tags) {
this.id = id;
this.title = title;
this.creationDateTime = creationDateTime;
this.resolveStatus = resolveStatus;
this.tags = tags;
}
@Override
public String toString() {
return "StandardThreadResponseDTO{" +
"id=" + id +
", title='" + title + '\'' +
", creationDateTime=" + creationDateTime +
", resolveStatus=" + resolveStatus +
", tags=" + tags +
'}';
}
}
以下是我的函数调用
@Test
public void testingThreadCreation(){
//Generating Category
Category category = threadRepository.createCategory(ThreadCategoryEnum.ADVICE.name());
System.out.println(category.getId());
//Generating Account Type
List<AccountTypeEnum> types = new ArrayList<>();
types.add(AccountTypeEnum.NORMAL_USER);
AccountType accountType= forumAccountRepository.createAccountType( "NORMAL_USER", types);
//Generating Account
ForumAccount newAccount = forumAccountRepository.createNewAccount("TrungLuong0806", passwordEncoder.encode("TestAccount123"), "[email protected]");
System.out.println(newAccount.getId());
//Generate Tags
Tag tag_1 = tagRepository.createNewTag("LateralRaise");
Tag tag_2 = tagRepository.createNewTag("ShoulderWorkout");
Set<Tag> tags = new HashSet<>();
tags.add(tag_1);
tags.add(tag_2);
//Generate Threads
//Thread thread = threadRepository.addNewThread(newAccount.getId(), "Is Lateral Raise an optimal exercises for shoulders", ToxicStatusEnum.NOT_TOXIC.name(), tags);
Thread thread = threadRepository.addNewThread(newAccount.getId(), "Is Lateral Raise an optimal exercises for shoulders", ToxicStatusEnum.NOT_TOXIC.name(), tags, category.getId());
System.out.println("Thread ID: " + thread.getId());
System.out.println(threadRepository.findTagsInThread(thread.getId()));
//Fetch all threads created by the user
System.out.println(threadRepository.getThreadsByAccountId(newAccount.getId(), 0, 5));
}
我已经确认函数调用导致创建具有正确关系的新标签。但是,调用 threadRepository.getThreadsByAccountId(newAccount.getId(), 0, 5) 会返回带有空标签集的正确线程参数,考虑到所有标签均已正确创建,这种情况不应该发生:
[StandardThreadResponseDTO{id=2e108544-52e9-4c2d-bd9b-62bd88bd1be9, title='Is Lateral Raise an optimal exercises for shoulders', creationDateTime=2024-10-09T01:54:17.731, resolveStatus=false, tags=[]}]
你能告诉我为什么标签集合是空的吗?我已确保为 DTO 使用匹配的字段名称
提取“collect”中的嵌套语句,即使使用子查询也是“call {....}”
@Query("MATCH (author:ForumAccount {id: $accountId})-[:CREATES]->(thread:Thread {toxicStatus: 'NOT_TOXIC'}) " +
"OPTIONAL MATCH (thread)-[:CONTAINS_TAGS]->(tag:Tag) " +
"WITH thread, COLLECT(tag.tagName) AS tn " +
"RETURN thread.id AS id, thread.title AS title, thread.resolveStatus AS resolveStatus, " +
"thread.creationDateTime AS creationDateTime, 0 AS likeCount, 0 AS postCount, 0 AS viewCount, " +
"tn " +
"ORDER BY thread.creationDateTime " +
"SKIP $offset LIMIT $limit")
使用子查询
@Query("MATCH (author:ForumAccount {id: $accountId})-[:CREATES]->(thread:Thread {toxicStatus: 'NOT_TOXIC'}) " +
"CALL { " +
" WITH thread " +
" OPTIONAL MATCH (thread)-[:CONTAINS_TAGS]->(tag:Tag) " +
" RETURN COLLECT(tag.tagName) AS tags " +
"} AS tagCollection " +
"RETURN thread.id AS id, thread.title AS title, thread.resolveStatus AS resolveStatus, " +
"thread.creationDateTime AS creationDateTime, 0 AS likeCount, 0 AS postCount, 0 AS viewCount, " +
"tagCollection.tags AS tags " +
"ORDER BY thread.creationDateTime " +
"SKIP $offset LIMIT $limit")