When i try to order the values of a related entity it throws an error:
query {
Chat {
id
messages(orderBy: [sentAt_desc]) {
text
sentAt {
year
month
day
}
sender {
id
name
}
}
}
}
Get this error:
Failed to invoke function `apoc.coll.sortMulti`: Caused by: java.lang.ClassCastException: java.util.HashMap cannot be cast to java.lang.Comparable
We are using:
Could you share your GraphQL type definitions so I can try to reproduce? (or at least the Chat and message types).
I'm assuming sentAt is a Date type?
sentAt is a DateTime type, here are the types definitios for Chat and Message:
type Chat {
id: String!
checkIn: DateTime
checkOut: DateTime
createdAt: DateTime!
updatedAt: DateTime!
roomNumber: Int!
owner: User! @relation(name: "OWNS", direction: "IN")
messages: [Message] @relation(name: "BELONGS_TO", direction: "IN")
hotel: Hotel @relation(name: "BELONGS_TO", direction: "OUT")
}
type Message {
id: String!
text: String!
sentAt: DateTime!
sender: User! @relation(name: "SENT", direction: "IN")
chat: Chat! @relation(name: "BELONGS_TO", direction: "OUT")
}
I'm facing the same problem with a DateTime field. Any news on this?
Hey, we are also dealing with this issue. We would like to refactor our code base to use Temporal values like DateTime, but ran into an issue when we try to use orderBy: createdAt_asc for nested attributes like comments on a Post
Post(id: "p15") {
comments(orderBy: createdAt_asc) {
content
createdAt {
formatted
}
}
}
In our case, the neo4j-graphql-js generated query look like this
MATCH (`post`:`Post` {id:$id, deleted:$deleted, disabled:$disabled}) WITH `post` ORDER BY post.createdAt DESC RETURN `post` { .deleted , .disabled , .id , .id , .title , .content , .contentExcerpt ,createdAt: { formatted: toString(`post`.createdAt) }, .disabled , .deleted , .slug , .image ,author: head([(`post`)<-[:`WROTE`]-(`post_author`:`User`) | post_author { .id , .slug , .name , .avatar , .disabled , .deleted ,shoutedCount: apoc.cypher.runFirstColumn("MATCH (this)-[: SHOUTED]->(r: Post) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)", {this: post_author, cypherParams: $cypherParams}, false),contributionsCount: apoc.cypher.runFirstColumn("MATCH (this)-[: WROTE]->(r: Post)
WHERE NOT r.deleted = true AND NOT r.disabled = true
RETURN COUNT(r)", {this: post_author, cypherParams: $cypherParams}, false),commentedCount: apoc.cypher.runFirstColumn("MATCH (this)-[: WROTE]->(: Comment)-[: COMMENTS]->(p: Post) WHERE NOT p.deleted = true AND NOT p.disabled = true RETURN COUNT(DISTINCT(p))", {this: post_author, cypherParams: $cypherParams}, false),followedByCount: apoc.cypher.runFirstColumn("MATCH (this)<-[: FOLLOWS]-(r: User) RETURN COUNT(DISTINCT r)", {this: post_author, cypherParams: $cypherParams}, false),followedByCurrentUser: apoc.cypher.runFirstColumn("MATCH (this)<-[: FOLLOWS]-(u: User { id: $cypherParams.currentUserId})
RETURN COUNT(u) >= 1", {this: post_author, cypherParams: $cypherParams}, false),location: head([ post_author_location IN apoc.cypher.runFirstColumn("MATCH (this)-[: IS_IN]->(l: Location) RETURN l", {this: post_author, cypherParams: $cypherParams}, true) | post_author_location { .nameEN }]) ,badges: [(`post_author`)<-[:`REWARDED`]-(`post_author_badges`:`Badge`) | post_author_badges { .id , .icon }] }]) ,tags: [(`post`)-[:`TAGGED`]->(`post_tags`:`Tag`) | post_tags { .id }] ,categories: [(`post`)-[:`CATEGORIZED`]->(`post_categories`:`Category`) | post_categories { .id , .name , .icon }] ,commentsCount: apoc.cypher.runFirstColumn("MATCH (this)<-[: COMMENTS]-(r: Comment) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)", {this: post, cypherParams: $cypherParams}, false),shoutedCount: apoc.cypher.runFirstColumn("MATCH (this)<-[: SHOUTED]-(r: User) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)", {this: post, cypherParams: $cypherParams}, false),shoutedByCurrentUser: apoc.cypher.runFirstColumn("MATCH (this)<-[: SHOUTED]-(u: User { id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1", {this: post, cypherParams: $cypherParams}, false),emotionsCount: apoc.cypher.runFirstColumn("MATCH (this)<-[emoted: EMOTED]-(: User) RETURN COUNT(DISTINCT emoted)", {this: post, cypherParams: $cypherParams}, false),comments: [sortedElement IN apoc.coll.sortMulti([(`post`)<-[:`COMMENTS`]-(`post_comments`:`Comment`) | post_comments { .deleted , .disabled , .id , .id ,createdAt: `post_comments`.createdAt, .disabled , .deleted , .content , .contentExcerpt ,author: head([(`post_comments`)<-[:`WROTE`]-(`post_comments_author`:`User`) | post_comments_author { .id , .slug , .name , .avatar , .disabled , .deleted ,shoutedCount: apoc.cypher.runFirstColumn("MATCH (this)-[: SHOUTED]->(r: Post) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)", {this: post_comments_author, cypherParams: $cypherParams}, false),contributionsCount: apoc.cypher.runFirstColumn("MATCH (this)-[: WROTE]->(r: Post)
WHERE NOT r.deleted = true AND NOT r.disabled = true
RETURN COUNT(r)", {this: post_comments_author, cypherParams: $cypherParams}, false),commentedCount: apoc.cypher.runFirstColumn("MATCH (this)-[: WROTE]->(: Comment)-[: COMMENTS]->(p: Post) WHERE NOT p.deleted = true AND NOT p.disabled = true RETURN COUNT(DISTINCT(p))", {this: post_comments_author, cypherParams: $cypherParams}, false),followedByCount: apoc.cypher.runFirstColumn("MATCH (this)<-[: FOLLOWS]-(r: User) RETURN COUNT(DISTINCT r)", {this: post_comments_author, cypherParams: $cypherParams}, false),followedByCurrentUser: apoc.cypher.runFirstColumn("MATCH (this)<-[: FOLLOWS]-(u: User { id: $cypherParams.currentUserId})
RETURN COUNT(u) >= 1", {this: post_comments_author, cypherParams: $cypherParams}, false),location: head([ post_comments_author_location IN apoc.cypher.runFirstColumn("MATCH (this)-[: IS_IN]->(l: Location) RETURN l", {this: post_comments_author, cypherParams: $cypherParams}, true) | post_comments_author_location { .nameEN }]) ,badges: [(`post_comments_author`)<-[:`REWARDED`]-(`post_comments_author_badges`:`Badge`) | post_comments_author_badges { .id , .icon }] }]) }], ['^createdAt']) | sortedElement { .*, }] } AS `post`
and the error thrown in the console is
Error GraphQL error: Invalid input '}': expected whitespace, comment, literal entry, property selector, variable selector or all properties selector (line 7, column 512 (offset: 4643))
"RETURN COUNT(u) >= 1", {this: post_comments_author, cypherParams: $cypherParams}, false),location: head([ post_comments_author_location IN apoc.cypher.runFirstColumn("MATCH (this)-[: IS_IN]->(l: Location) RETURN l", {this: post_comments_author, cypherParams: $cypherParams}, true) | post_comments_author_location { .nameEN }]) ,badges: [(`post_comments_author`)<-[:`REWARDED`]-(`post_comments_author_badges`:`Badge`) | post_comments_author_badges { .id , .icon }] }]) }], ['^createdAt']) |
sortedElement { .*, }] } AS `post`"
^
Here is our Post and Comment schema in case it's helpful for anyone
type Post {
id: ID!
activityId: String
objectId: String
author: User @relation(name: "WROTE", direction: "IN")
title: String!
slug: String
content: String!
contentExcerpt: String
image: String
imageUpload: Upload
visibility: Visibility
deleted: Boolean
disabled: Boolean
disabledBy: User @relation(name: "DISABLED", direction: "IN")
createdAt: DateTime
updatedAt: String
language: String
relatedContributions: [Post]!
@cypher(
statement: """
MATCH (this)-[: TAGGED|CATEGORIZED]->(categoryOrTag)<-[: TAGGED|CATEGORIZED]-(post:
Post)
WHERE NOT post.deleted AND NOT post.disabled
RETURN DISTINCT post
LIMIT 10
"""
)
tags: [Tag]! @relation(name: "TAGGED", direction: "OUT")
categories: [Category]! @relation(name: "CATEGORIZED", direction: "OUT")
comments: [Comment]! @relation(name: "COMMENTS", direction: "IN")
commentsCount: Int!
@cypher(
statement: "MATCH (this)<-[: COMMENTS]-(r: Comment) WHERE NOT r.deleted = true AND NOT
r.disabled = true RETURN COUNT(DISTINCT r)"
)
shoutedBy: [User]! @relation(name: "SHOUTED", direction: "IN")
shoutedCount: Int!
@cypher(
statement: "MATCH (this)<-[: SHOUTED]-(r: User) WHERE NOT r.deleted = true AND NOT
r.disabled = true RETURN COUNT(DISTINCT r)"
)
# Has the currently logged in user shouted that post?
shoutedByCurrentUser: Boolean!
@cypher(
statement: "MATCH (this)<-[: SHOUTED]-(u: User { id: $cypherParams.currentUserId}) RETURN
COUNT(u) >= 1"
)
emotions: [EMOTED]
emotionsCount: Int!
@cypher(statement: "MATCH (this)<-[emoted: EMOTED]-(: User) RETURN COUNT(DISTINCT
emoted)")
}
input _PostInput {
id: ID!
}
type Mutation {
CreatePost(
id: ID
title: String!
slug: String
content: String!
image: String
imageUpload: Upload
visibility: Visibility
language: String
categoryIds: [ID]
contentExcerpt: String
): Post
UpdatePost(
id: ID!
title: String!
slug: String
content: String!
contentExcerpt: String
image: String
imageUpload: Upload
visibility: Visibility
language: String
categoryIds: [ID]
): Post
DeletePost(id: ID!): Post
AddPostEmotions(to: _PostInput!, data: _EMOTEDInput!): EMOTED
RemovePostEmotions(to: _PostInput!, data: _EMOTEDInput!): EMOTED
}
type Query {
PostsEmotionsCountByEmotion(postId: ID!, data: _EMOTEDInput!): Int!
PostsEmotionsByCurrentUser(postId: ID!): [String]
}
type Comment {
id: ID!
activityId: String
author: User @relation(name: "WROTE", direction: "IN")
content: String!
contentExcerpt: String
post: Post @relation(name: "COMMENTS", direction: "OUT")
createdAt: DateTime
updatedAt: String
deleted: Boolean
disabled: Boolean
disabledBy: User @relation(name: "DISABLED", direction: "IN")
}
type Mutation {
CreateComment(
id: ID
postId: ID!
content: String!
contentExcerpt: String
deleted: Boolean
disabled: Boolean
): Comment
UpdateComment(
id: ID!
content: String!
contentExcerpt: String
deleted: Boolean
disabled: Boolean
): Comment
DeleteComment(id: ID!): Comment
}
Wanna say a big thank you to @johnymontana and the other contributors to this library.
Maybe, we can help come to a solution for this issue.
Has anyone found a workaround or fix for this issue?
Thanks for pinging this @g3rd - will try to address it this week.
I suppose a temporary workaround might be to store an additional property that is the epoch milliseconds version of the timestamp as a Long and use that for ordering instead of the DateTime field?
I am facing the same problem on spatial Point as well.
Thanks for pinging this @g3rd - will try to address it this week.
I suppose a temporary workaround might be to store an additional property that is the epoch milliseconds version of the timestamp as a Long and use that for ordering instead of the DateTime field?
The proposed workaround works! Thanks!
This issue still occurs in 2.16.3 with nested requests such as:
query ($id: ID!, $first: Int!, $offset: Int!) {
User(id: $id) {
posts(first: $first, offset: $offset, orderBy: createdAt_desc) {
id
}
}
}
This issue still occurs in 2.16.3 with nested requests such as:
query ($id: ID!, $first: Int!, $offset: Int!) { User(id: $id) { posts(first: $first, offset: $offset, orderBy: createdAt_desc) { id } } }
Hi
Make sure you have installed the APOC library first
You can follow the instructions here : https://neo4j.com/labs/apoc/4.1/installation/
I installed https://github.com/neo4j-contrib/neo4j-apoc-procedures/releases/tag/4.1.0.2 the issue persists
Most helpful comment
Thanks for pinging this @g3rd - will try to address it this week.
I suppose a temporary workaround might be to store an additional property that is the epoch milliseconds version of the timestamp as a Long and use that for ordering instead of the DateTime field?