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天)
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),
3)设置并保持Neo4j连接信息
需要在 .env 文件中输入上一步中提到的选项卡信息:
NEO4J_URI,
NEO4J_USER,
NEO4J_PASSWORD
注意:需要Github或Google帐号登录才能保存输入的信息
(保存后,502错误信息消失)
4)测试codesandbox能否使用
点击右上角偏下一点的“ Open in New Window”图标,在新窗口中执行下面的GraphQL Query代码(Codesandbox 环境中的 GraphQL Playground 窗口)
{
books {
title
}
}
没有报错表示正常
在codesandbox中查看schema.graphql文件,其中有定义Type Book
此时启动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。
打开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中查询,数据如下图:
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信息。
在Neo4j Brower中查询,结果如下:
至此,一切正常。
最后奉上小测验
未完待续