Northwind 数据集的 GraphQL 建模

这是 GraphQL Library 7 版本的文档。对于长期支持 (LTS) 版本 5,请参考 GraphQL Library 5 LTS 版本

本教程使用 Neo4j GraphQL 库为 Northwind 示例数据集构建 API。

Northwind 数据集包含但不限于有关产品、供应商、订单和客户的数据。该模型非常适合用作网店 API。

先决条件

  1. 设置一个新的 AuraDB 实例。请参考 创建 Neo4j Aura 实例

  2. 使用 Northwind 数据集填充该实例。

    如果您已经完成了 GraphQL 和 Aura 控制台入门指南,并希望删除在那里创建的示例节点,请在向数据库填充 Northwind 数据集之前,在 Query 中运行以下代码

    MATCH (n) DETACH DELETE n;

    此 Cypher 查询将删除数据库中的所有数据。

    1. 在 Aura 中,选择 Learning(学习),然后在 Getting started(入门)下选择 Beginner(初学者)。

    2. 选择 Learn the basics(学习基础知识)磁贴,并在左侧菜单中滚动到第 4/11 页。

    3. 通过 Get the Northwind datset(获取 Northwind 数据集)触发导入,然后在右侧点击 Run import(运行导入)。

目标

连接到 Northwind 数据集的网店 API 应能够

  • 创建新客户

  • 下订单

  • 计算订单价格

  • 按供应商和类别筛选产品

请参阅 使用 API 获取示例实现。

创建 GraphQL 数据 API

有关如何执行此操作的步骤,请参阅 GraphQL 和 Aura 控制台。在本教程中,请确保 启用内省 (Enable introspection)启用字段建议 (Enable field suggestions)

类型定义

通过使用这些类型定义,使相关的节点和关系可用

type Customer @node {
    contactName: String!
    customerID: ID! @id
    orders: [Order!]! @relationship(type: "PURCHASED", direction: OUT)
}

type Order @node {
    orderID: ID! @id
    customer: [Customer!]! @relationship(type: "PURCHASED", direction: IN)
    products: [Product!]! @relationship(type: "ORDERS", direction: OUT, properties: "ordersProperties")
}

type Product @node {
    productName: String!
    category: [Category!]! @relationship(type: "PART_OF", direction: OUT)
    orders: [Product!]! @relationship(type: "ORDERS", direction: IN, properties: "ordersProperties")
    supplier: [Supplier!]! @relationship(type: "SUPPLIES", direction: IN)
}

type Category @node {
    categoryName: String!
    products: [Product!]! @relationship(type: "PART_OF", direction: IN)
}

type Supplier @node {
    supplierID: ID! @id
    companyName: String!
    products: [Product!]! @relationship(type: "SUPPLIES", direction: OUT)
}

type ordersProperties @relationshipProperties {
    unitPrice: Float!
    quantity: Int!
}

导航至 Apollo Studio 网站,并将您的 GraphQL 数据 API URL 粘贴到 Sandbox(沙盒)输入框中。点击齿轮图标,在 Shared headers(共享头信息)下添加 x-api-key 和数据 API 的 API 密钥,然后 保存 (Save)

确保 API 正常工作

验证 Northwind 数据集的相关部分是否可访问

query {
    categories {
      categoryName
    }
}

您应该在 Response(响应)中看到

{
  "data": {
    "categories": [
      {
        "categoryName": "Beverages"
      },
      {
        "categoryName": "Condiments"
      },
      {
        "categoryName": "Confections"
      },
      {
        "categoryName": "Dairy Products"
      },
      {
        "categoryName": "Grains/Cereals"
      },
      {
        "categoryName": "Meat/Poultry"
      },
      {
        "categoryName": "Produce"
      },
      {
        "categoryName": "Seafood"
      }
    ]
  }
}

使用 API

以下部分提供了如何在网店场景中使用 API 的简单示例。

创建新客户

以下 mutation 创建了一个名为 "Jane Doe" 的新客户

mutation {
  createCustomers(
    input: [{
      contactName: "Jane Doe"
    }]
  ) {
    customers {
      contactName
    }
  }
}

为了使其通用,您可以使用 GraphQL 变量 来动态设置 contactName

mutation CreateCustomer($contactName: String!) {
  createCustomers(
    input: [{
      contactName: $contactName
    }]
  ) {
    customers {
      contactName
      customerID
    }
  }
}

下订单

要下订单,需创建一个链接到多个产品节点和一个客户节点的新订单节点

mutation {
  createOrders(
    input: {
      customer: {
        connect: { where: { node: { contactName: { eq: "Jane Doe" } } } }
      }
      products: {
        connect: {
          edge: { unitPrice: 23.25, quantity: 5 }
          where: { node: { productName: { eq: "Tofu" } } }
        }
      }
    }
  ) {
    orders {
      orderID
    }
  }
}

下订单时,客户和产品信息必须已知或已收集。客户端的购物车通常会处理并显示此信息。

计算订单价格

要计算订单价格,请查询 order 操作字段并使用 orderID 过滤器筛选订单。然后,从连接 OrderProduct 节点的 ORDERS 关系中访问关系属性 quantityunitPrice

query {
  orders(where: { orderID: { eq: "6a5572bb-41fb-4263-913c-69c678c04766"} }) {
    products {
      productName
    }
    orderID
    productsConnection {
      edges {
        properties {
          quantity
          unitPrice
        }
      }
    }
  }
}

结果如下所示

{
  "data": {
    "orders": [
      {
        "products": [
          {
            "productName": "Tofu"
          }
        ],
        "orderID": "6a5572bb-41fb-4263-913c-69c678c04766",
        "productsConnection": {
          "edges": [
            {
              "properties": {
                "quantity": 5,
                "unitPrice": 23.25
              }
            }
          ]
        }
      }
    ]
  }
}

quantityunitPrice 的乘积即为总成本,在本例中为 116.25。

请注意,ORDERS 关系上没有 discount 字段,且在该场景中税务的处理方式尚不明确。

筛选产品

要按类别和供应商筛选产品,首先查询 categoryName 和供应商 companyName

query {
    categories {
      categoryName
    }
    suppliers {
      companyName
    }
}

后续查询现在可以生成筛选后的产品列表。对于特定类别的产品

query {
  products(where: {categoryConnection: {all: {node: {categoryName: {eq: "Produce"}}}}}) {
    productName
  }
}

结果

{
  "data": {
    "products": [
      {
        "productName": "Uncle Bob's Organic Dried Pears"
      },
      {
        "productName": "Tofu"
      },
      {
        "productName": "Rössle Sauerkraut"
      },
      {
        "productName": "Manjimup Dried Apples"
      },
      {
        "productName": "Longlife Tofu"
      }
    ]
  }
}

同样,按供应商筛选如下所示

query {
  products(where: {supplierConnection: {some: {node: {companyName: {eq: "New England Seafood Cannery"}}}}}) {
    productName
  }
}

结果

{
  "data": {
    "products": [
      {
        "productName": "Boston Crab Meat"
      },
      {
        "productName": "Jack's New England Clam Chowder"
      }
    ]
  }
}
  • 有关如何使用 GraphQL 库处理唯一标识符的更多信息,请参阅 @id

  • 有关使用 GraphQL 库访问关系属性的详细信息,请参阅 @relationshipProperties

  • 有关如何使用 GraphQL 库应用过滤器的更多信息,请参阅 过滤 (Filtering)