如何在Neo4j中撰写查询?

时间:2015-11-12 04:54:14

标签: neo4j

我想根据通用结构(很像GraphQL)定义我的Neo4j查询并组合它们。 例如,这是一个没有组合的简单查询:

chatrooms: {
  query: {limit: 10}
  fields: {
    id: true,
    name: true }}

我的Neo4j翻译可能如下所示:

chatrooms = ({query, fields}) ->
  """
    MATCH (c:CHATROOMS)
    RETURN #{R.join(' ', R.map(R.concat('c.'), R.keys(fields)))}
    LIMIT #{query.limit}
  """

但是当我想要构建更深层次的嵌套查询时,我遇到了麻烦。 例如,如果我想要一些关于每个聊天室所有者的信息怎么办?我应该能够一次查询所有这些,而不是花费两次往返HTTP请求。

chatrooms: {
  query: {limit: 10}
  fields: {
    id: true,
    name: true
    owner: {
      fields: {
        id: true,
        name: true}}}}

此时,我有点挂了。 我不知道如何使解释器足够通用以处理这些情况。 我知道查询看起来应该是这样的。

MATCH (c:CHATROOM)
MATCH (c)<-[:OWNS]-(u:USER)
RETURN c.id, c.name, u.id, u.name
LIMIT 10

理想情况下,此查询将返回具有类似结构的内容:

[
  {id: 1, name:'neo4j', owner: {id: 99, name: 'michael'}}
  {id: 2, name:'meteor', owner: {id: 100, name: 'chet'}}
]

这样可以使结果的组合和解释变得更加容易,但这是后来的细节。

最后,我无法更深入地嵌套这些查询。 例如,如果我还想为每个聊天室添加一些消息,该怎么办? 如果我想了解每个聊天室所有者的一些信息怎么办?

chatrooms: {
  query: {limit: 10}
  fields: {
    id: true,
    name: true
    owner: {
      fields: {
        id: true,
        name: true}}
    messages: {
      query: {limit: 20}
      fields: {
        id: true,
        text: true,
        createdAt: true,
        owner: {
          fields: {
            id: true,
            name: true }}}}}}

这是我的理由 - 虽然我很确定它是完全错误的。

MATCH (c:CHATROOM)
MATCH (c)<-[:OWNS]-(u:USER)
UNWIND c as room
  MATCH (room)-[:OWNS]->(m:MESSAGE)
  MATCH (m)<-[:OWNS]-(x:USER)
  RETURN collect(m.id, m.text, m.creatdAt, x.id, x.name)
  LIMIT 20
RETURN c.id, c.name, u.id, u.name, 
LIMIT 10

无论如何,目标是能够指定一个巨大的嵌套查询,并能够在一个HTTP请求中运行它。 也许有必要对输出进行一些解析,但理想情况下,我将获得与输出相当的数据结构。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

首先,GraphQL哲学还有嵌套结构。

您应该使用引用。

e.g。

chatrooms: {
  query: {limit: 10}
  fields: {
    id: true,
    name: true
    owner: ${owner.id}
  messages: {
    query: {limit: 20}
    fields: {
      id: true,
      text: true,
      createdAt: true,
      owner: ${owner.id}
    }
  }
} 

owners: [{id: 1, fields: { id: true, name: true}}]

为什么在根对象中使用fields属性而不是字段?

答案 1 :(得分:1)

您可以使用collect({key:value}){key:collect(value)的序列和组合。

MATCH (c:CHATROOM)<-[:OWNS]-(u:USER)
RETURN {id: c.id, name: c.name, owner: collect({id: u.id, name: u.name})} AS data
LIMIT 10

然后使用这些数据:

create (c:CHATROOM {id:1, name:"neo4j"})<-[:OWNS]-(u:USER {id:99,name:"Michael") 
create (c:CHATROOM {id:2, name:"meteor"})<-[:OWNS]-(u:USER {id:100,name:"Chet")

运行你得到的查询

+--------------------------------------------------------------------+
| data                                                               |
+--------------------------------------------------------------------+
| {id=2, name=meteor, owner=[{id=100, name=Chet}]}                   |
| {id=1, name=neo4j, owner=[{id=99, name=Michael}]}                  |
+--------------------------------------------------------------------+

住在这里:http://console.neo4j.org/r/d41luc

要将两个行合并为一个,您可以使用WITH然后使用RETURN,但之后您将无法获得将数据流式传输回来的好处。

MATCH (c:CHATROOM)<-[:OWNS]-(u:USER)
WITH {id: c.id, name: c.name, owner: collect({id: u.id, name: u.name})} AS row
RETURN collect(row) as data
LIMIT 10

更新

请使用更具描述性的关系类型,而不仅仅是:OWNS

MATCH (c:CHATROOM)<-[:OWNS]-(u:USER)
MATCH (c)-[:OWNS]->(m:MESSAGE)<-[:OWNS]-(x:USER)
WITH u,c,collect({id: m.id, text: m.text, created_at: m.createdAt, author_id: x.id, author: x.name}) as messages[0..20]
RETURN collect({ id: c.id, room: c.name, 
                 owner_id: u.id, owner: u.name, 
                 messages: messages}) as rooms
LIMIT 10