如何使用Neo4j GraphQL Library(二)

https://neo4j.com/graphacademy/training-graphql-apis/02-graphql-apis-overview-of-neo4j-graphql/

1.概述

使用Neo4j GraphQL Library为在线书店构建GraphQL API,包括:
1)使用Codesandbox and Neo4j Sandbox配置在线开发环境
2)使用GraphQL Type定义Neo4j图数据模型
3)使用Neo4j GraphQL Library创建GraphQL API
4)使用GraphQL Mutation创建数据
5)使用GraphQL Query查询数据

2.环境配置

目的:可以使用浏览器基于 Codesandbox 运行 Node.js JavaScript 代码

1)创建一个空的 Neo4j Sandbox 项目

https://sandbox.neo4j.com/

记住"Connection details"选项卡中的信息,后面会用到
注意:每个sandbox项目有效期是3天,仅可以续期一次(7天)

520-1.JPG

2)打开 codesandbox

https://codesandbox.io/s/github/johnymontana/training-v3/tree/master/modules/graphql-apis/supplemental/code/02-graphql-apis-overview-of-neo4j-graphql/begin?file=/.env

第一次进入时页面会报错(502: Bad Gateway),


520-2.JPG

3)设置并保持Neo4j连接信息

需要在 .env 文件中输入上一步中提到的选项卡信息:
NEO4J_URI,
NEO4J_USER,
NEO4J_PASSWORD

注意:需要Github或Google帐号登录才能保存输入的信息


520-3.JPG

(保存后,502错误信息消失)

4)测试codesandbox能否使用

点击右上角偏下一点的“ Open in New Window”图标,在新窗口中执行下面的GraphQL Query代码(Codesandbox 环境中的 GraphQL Playground 窗口)

{
  books {
    title
  }
}

没有报错表示正常
在codesandbox中查看schema.graphql文件,其中有定义Type Book


520-4.JPG

此时启动neo4j sandbox project,进入Neo4j Browers,输入Cyper:match(n) return n,是不能查询到任何图数据的,因为此时是个空的图数据库。

3. GraphQL Type 定义

即定义数据类型,包括属性和关系等

下图是在线书店的图谱,包括节点/属性和关系,如:节点-Book,有属性title/price/description;关系-AUTHOR_OF,关系指向的节点-Author,有属性name。
节点对应GraphQL Type,属性对应GraphQL Fields。


520-5.png

打开schema.graphql文件,确定已经定义了如下Type

#schema.graphql

type Order {
  orderID: ID! @id
  placedAt: DateTime @timestamp
  shippingCost: Float
  shipTo: Address @relationship(type: "SHIPS_TO", direction: OUT)
  customer: Customer @relationship(type: "PLACED", direction: IN)
  books: [Book] @relationship(type: "CONTAINS", direction: OUT)
}

type Customer {
  username: String
  orders: [Order] @relationship(type: "PLACED", direction: OUT)
  reviews: [Review] @relationship(type: "WROTE", direction: OUT)
}

type Address {
  address: String
  location: Point
  order: Order @relationship(type: "SHIPS_TO", direction: IN)
}

type Book {
  isbn: ID!
  title: String
  price: Float
  description: String
  reviews: [Review] @relationship(type: "REVIEWS", direction: IN)
}

type Review {
  rating: Int
  text: String
  createdAt: DateTime @timestamp
  book: Book @relationship(type: "REVIEWS", direction: OUT)
  author: Customer @relationship(type: "WROTE", direction: IN)
}

代码解释:

orderID: ID! @id
orderID 表示属性-订单编号
ID 表示订单编号是唯一的
! 表示订单编号不能为空,不接受null也不能被省略
@id表示系统自动生成订单编号

placedAt: DateTime @timestamp
DataTime 也是一个 Scalar 标量类型
@timestamp 表示节点创建或更新时自动写入系统时间

shipTo: Address @relationship(type: "SHIPS_TO", direction: OUT)
Address 表示Address节点,一个Graph Type
@relationship 定义了Order节点与Address节点的关系
type 表示两个节点关系的名称是SHIPS_TO
direction 表示关系的箭头方向,IN-箭头向自己,OUT-箭头向对方

books: [Book] @relationship(type: "CONTAINS", direction: OUT)
[Book] 其中的[]表示Order节点与Book节点的关系是1对多,[]用来表示列表list

顺便说说GraphQL的 Type System 类型体系:
ID、Time、Url、Int、Float、String、Boolean,同属于一种类型 Scalar 标量类型。
除标量以外的另四种基础类型是:Object 对象、Enum 枚举、Interface 接口、Union 联合。

Object 对象 示例:
对象对应到图数据中的节点,下面的name/age/picture对应节点的属性。

type Person {
  name: String
  age: Int
  picture: Url
}

Enum 枚举:
可能值的一个有限集合,例如:性别包括男、女。

Interface 接口示例:
下面代码中第一个是接口,后面两个是实现了接口的对象。
如果学过JAVA等编程需要,不难理解对象和接口的概念。

interface NamedEntity {
  name: String
}

type Person implements NamedEntity {
  name: String
  age: Int
}

type Business implements NamedEntity {
  name: String
  employeeCount: Int
}

Union 联合示例:
下面代码将两个对象做了联合;
针对联合做查询时需要识别是哪个对象。

union SearchResult = Photo | Person

type Person {
  name: String
  age: Int
}

type Photo {
  height: Int
  width: Int
}

type SearchQuery {
  firstSearchResult: SearchResult
}

4. 往书店添加数据

首先添加一条书籍信息
这里只是添加了书籍对象(节点)的属性,没有定义关系。

mutation {
  createBooks(
    input: {
      isbn: "1492047686"
      title: "Graph Algorithms"
      price: 37.48
      description: "Practical Examples in Apache Spark and Neo4j"
    }
  ) {
    books {
      isbn
      title
      price
      description
      __typename
    }
  }
}

执行结束后,启动neo4j sandbox project,进入Neo4j Browers,输入Cypher:match(n) return n,是能够查询到一条book信息的

再添加一条评价信息
该评价信息通过书籍标题将Review节点和Book节点建立了关系

mutation {
  createReviews(
    input: {
      rating: 5
      text: "Best overview of graph data science!"
      book: { connect: { where: { title: "Graph Algorithms" } } }
    }
  ) {
    reviews {
      rating
      text
      createdAt
      book {
        title
      }
    }
  }
}

接着添加其他的节点和关系

mutation {
  createCustomers(
    input: {
      username: "EmilEifrem7474"
      reviews: {
        connect: { where: { text: "Best overview of graph data science!" } }
      }
      orders: {
        create: {
          books: { connect: { where: { title: "Graph Algorithms" } } }
          shipTo: {
            create: {
              address: "111 E 5th Ave, San Mateo, CA 94401"
              location: {
                latitude: 37.5635980790
                longitude: -122.322243272725
              }
            }
          }
        }
      }
    }
  ) {
    customers {
      username
      orders {
        placedAt
        books {
          title
        }
        shipTo {
          address
        }
      }
      reviews {
        text
        rating
        book {
          title
        }
      }
    }
  }
}

上面的代码添加了Customer数据,代码执行结束后会返回指定的信息,代码结构如下:

mutation {
  createCustomers(
    添加数据
  ) { 
    返回信息  
  }
}

Mutation除了创建数据之外,也可以更新和删除数据,详见文档:
https://neo4j.com/docs/graphql-manual/current/schema/mutations/

5. 清除数据,然后导入干净的示例数据

清除数据
清除上面的代码添加的数据,在Neo4j sandbox project中,点击Open,进入Neo4j Browers,执行如下Cypher:

MATCH (a) DETACH DELETE a

警告:执行该代码会清除Neo4j图数据库中的所有数据,请不要执行错了环境。

导入示例数据
在清除了所有数据后导入干净的示例数据。

mutation {
  createBooks(
    input: [
      {
        isbn: "1492047686"
        title: "Graph Algorithms"
        price: 37.48
        description: "Practical Examples in Apache Spark and Neo4j"
      }
      {
        isbn: "1119387507"
        title: "Inspired"
        price: 21.38
        description: "How to Create Tech Products Customers Love"
      }
      {
        isbn: "190962151X"
        title: "Ross Poldark"
        price: 15.52
        description: "Ross Poldark is the first novel in Winston Graham's sweeping saga of Cornish life in the eighteenth century."
      }
    ]
  ) {
    books {
      title
    }
  }

  createCustomers(
    input: [
      {
        username: "EmilEifrem7474"
        reviews: {
          create: {
            rating: 5
            text: "Best overview of graph data science!"
            book: { connect: { where: { isbn: "1492047686" } } }
          }
        }
        orders: {
          create: {
            books: { connect: { where: { title: "Graph Algorithms" } } }
            shipTo: {
              create: {
                address: "111 E 5th Ave, San Mateo, CA 94401"
                location: {
                  latitude: 37.5635980790
                  longitude: -122.322243272725
                }
              }
            }
          }
        }
      }
      {
        username: "BookLover123"
        reviews: {
          create: [
            {
              rating: 4
              text: "Beautiful depiction of Cornwall."
              book: { connect: { where: { isbn: "190962151X" } } }
            }
          ]
        }
        orders: {
          create: {
            books: {
              connect: [
                { where: { title: "Ross Poldark" } }
                { where: { isbn: "1119387507" } }
                { where: { isbn: "1492047686" } }
              ]
            }
            shipTo: {
              create: {
                address: "Nordenskiöldsgatan 24, 211 19 Malmö, Sweden"
                location: { latitude: 55.6122270502, longitude: 12.99481772774 }
              }
            }
          }
        }
      }
    ]
  ) {
    customers {
      username
    }
  }
}

在Neo4j Browers中查询,数据如下图:


520-6.JPG

6. 使用GraphQL查询数据

查询代码

{
  books {
    title
  }
}

返回信息,返回了3条书籍的标题

{
  "data": {
    "books": [
      {
        "title": "Graph Algorithms"
      },
      {
        "title": "Inspired"
      },
      {
        "title": "Ross Poldark"
      }
    ]
  }
}

更复杂的查询代码这里就不贴出来了

7. 查询可以添加 where 和 options

options

可以用来排序、分页,例如:
按price倒序排序,limit 1 取一条数据,skip 0 跳过0条数据

{
  books(options: { sort: { price: DESC }, limit: 1, skip: 0 }) {
    title
    price
  }
}

详见文档:
https://neo4j.com/docs/graphql-manual/current/schema/pagination/

where

可以用来过滤数据,例如:
价格小于20的书籍Book

{
  books(where: { price_LT: 20.00 }) {
    title
    price
  }
}

_LT 表示小于 less than
-GT 表示大于 greater than

8. 额外的练习

打开 schema.graphql文件,添加数据类型Type:Author 和 Subject
同时Book也需要相应的调整,增加了与Author和Subject的关系

type Book {
  isbn: ID!
  title: String
  price: Float
  description: String
  reviews: [Review] @relationship(type: "REVIEWS", direction: IN)
  authors: [Author] @relationship(type: "AUTHOR_OF", direction: IN)
  subjects: [Subject] @relationship(type: "ABOUT", direction: OUT)
}

type Author {
  name: String
  book: [Book] @relationship(type: "AUTHOR_OF", direction: OUT)
}

type Subject {
  name: String
  book: [Book] @relationship(type: "ABOUT", direction: IN)
}

执行GraphQL Mutation,加入Author数据;
需要建立作者Author和书籍Book的关系。
其中有一本书有两个作者,即添加了4个作者-关联了3本书。

mutation {
  createAuthors(
    input: [
      {
      name: "Marty Cagan"
      book: { connect: { where: { title: "Inspired" } } }
        }
      {
      name: "Winston Graham"
      book: { connect: { where: { title: "Ross Poldark" } } }
        }
      {
      name: "Mark Needham"
      book: { connect: { where: { title: "Graph Algorithms" } } }
        }
      {
      name: "Amy E. Hodler"
      book: { connect: { where: { title: "Graph Algorithms" } } }
        }
    ]
  ) {
    authors {
      name
      book {
        title
      }
    }
  }
}

如果执行GraphQL Query 或 Mutation 报错:

{
  "error": "Unexpected token < in JSON at position 0"
}

???,查了半天,发现是IN、OUT没有大写。

执行GraphQL Mutation,加入Subject数据;
需要建立题材Subject和书籍Book的关系。
一本书可以属于多个题材,对应的3本书添加了6个题材数据。

mutation {
  createSubjects(
    input: [
      {
      name: "Product management"
      book: { connect: { where: { title: "Inspired" } } }
        }
      {
      name: "Design"
      book: { connect: { where: { title: "Inspired" } } }
        }
      {
      name: "Historical fiction"
      book: { connect: { where: { title: "Ross Poldark" } } }
        }
      {
      name: "Cornwall"
      book: { connect: { where: { title: "Ross Poldark" } } }
        }
      {
      name: "Graph theory"
      book: { connect: { where: { title: "Graph Algorithms" } } }
        }
      {
      name: "Neo4j"
      book: { connect: { where: { title: "Graph Algorithms" } } }
        }
    ]
  ) {
    subjects {
      name
      book {
        title
      }
    }
  }
}

执行成功,返回6条Subject信息。


521-2.JPG

在Neo4j Brower中查询,结果如下:


521.JPG

至此,一切正常。

最后奉上小测验

q1.JPG

q2.JPG
q3.JPG

未完待续

你可能感兴趣的:(如何使用Neo4j GraphQL Library(二))