ウェアハウス管理システム
この「ウェアハウス管理システム」の例では、アプリの一般的なアクセスパターンを構成する方法を学びます。この例には以下のタイプがあります。
- Warehouse
- Product
- Inventory
- Employee
- AccountRepresentative
- Customer
これらのタイプには、次の一般的なアクセスパターンがあります。
- 従業員IDで従業員の詳細を検索
- 従業員名で従業員の詳細をクエリ
- 従業員の電話番号を検索
- 顧客の電話番号を検索
- 指定された日付範囲内で特定の顧客の注文を取得
- 指定された日付範囲内のすべてのオープン注文をすべての顧客全体で表示
- 最近採用されたすべての従業員を表示
- 特定のウェアハウスで働いているすべての従業員を検索
- 特定の製品に関して注文されているすべてのアイテムを取得
- すべてのウェアハウスで特定の製品の現在の在庫を取得
- 営業担当者別の顧客を取得
- 営業担当者と日付別の注文を取得
- 特定の製品に関して注文されているすべてのアイテムを取得
- 指定されたジョブタイトルを持つすべての従業員を取得
- 製品とウェアハウス別に在庫を取得
- 総製品在庫を取得
- 注文総額と営業期間でランク付けされた営業担当者を取得
以下のスキーマは、これらのアクセスパターンをサポートするために必要なインデックスと関係を紹介しています。
# This "input" configures a global authorization rule to enable public access to# all models in this schema. Learn more about authorization rules here: https://docs.amplify.aws/cli/graphql/authinput AMPLIFY { globalAuthRule: AuthRule = { allow: public } } # FOR TESTING ONLY!
type Order @model { id: ID! customerID: ID! @index(name: "byCustomerByStatusByDate", sortKeyFields: ["status", "date"]) @index(name: "byCustomerByDate", sortKeyFields: ["date"]) accountRepresentativeID: ID! @index(name: "byRepresentativebyDate", sortKeyFields: ["date"]) productID: ID! @index(name: "byProduct", sortKeyFields: ["id"]) status: String! amount: Int! date: String!}
type Customer @model { id: ID! name: String! phoneNumber: String accountRepresentativeID: ID! @index(name: "byRepresentative", sortKeyFields: ["id"]) ordersByDate: [Order] @hasMany(indexName: "byCustomerByDate", fields: ["id"]) ordersByStatusDate: [Order] @hasMany(indexName: "byCustomerByStatusByDate", fields: ["id"])}
type Employee @model { id: ID! name: String! @index(name: "byName", queryField: "employeeByName", sortKeyFields: ["id"]) startDate: String! phoneNumber: String! warehouseID: ID! @index(name: "byWarehouse", sortKeyFields: ["id"]) jobTitle: String! @index(name: "byTitle", queryField: "employeesByJobTitle", sortKeyFields: ["id"]) newHire: String! @index(name: "newHire", queryField: "employeesNewHire", sortKeyFields: ["id"]) @index(name: "newHireByStartDate", queryField: "employeesNewHireByStartDate", sortKeyFields: ["startDate"])}
type Warehouse @model { id: ID! employees: [Employee] @hasMany(indexName: "byWarehouse", fields: ["id"])}
type AccountRepresentative @model { id: ID! customers: [Customer] @hasMany(indexName: "byRepresentative", fields: ["id"]) orders: [Order] @hasMany(indexName: "byRepresentativebyDate", fields: ["id"]) orderTotal: Int salesPeriod: String @index(name: "bySalesPeriodByOrderTotal", queryField: "repsByPeriodAndTotal", sortKeyFields: ["orderTotal"])}
type Inventory @model { productID: ID! @primaryKey(sortKeyFields: ["warehouseID"]) warehouseID: ID! @index(name: "byWarehouseID", queryField: "itemsByWarehouseID") inventoryAmount: Int!}
type Product @model { id: ID! name: String! orders: [Order] @hasMany(indexName: "byProduct", fields: ["id"]) inventories: [Inventory] @hasMany(fields: ["id"])}スキーマを作成したので、操作するデータベース内のアイテムを作成しましょう。
# firstmutation createWarehouse { createWarehouse(input: {id: "1"}) { id }}
# secondmutation createEmployee { createEmployee(input: { id: "amanda" name: "Amanda", startDate: "2018-05-22", phoneNumber: "6015555555", warehouseID: "1", jobTitle: "Manager", newHire: "true"} ) { id jobTitle name newHire phoneNumber startDate warehouseID }}
# thirdmutation createAccountRepresentative { createAccountRepresentative(input: { id: "dabit" orderTotal: 400000 salesPeriod: "January 2019" }) { id orderTotal salesPeriod }}
# fourthmutation createCustomer { createCustomer(input: { id: "jennifer_thomas" accountRepresentativeID: "dabit" name: "Jennifer Thomas" phoneNumber: "+16015555555" }) { id name accountRepresentativeID phoneNumber }}
# fifthmutation createProduct { createProduct(input: { id: "yeezyboost" name: "Yeezy Boost" }) { id name }}
# sixthmutation createInventory { createInventory(input: { productID: "yeezyboost" warehouseID: "1" inventoryAmount: 300 }) { productID inventoryAmount warehouseID }}
# seventhmutation createOrder { createOrder(input: { amount: 300 date: "2018-07-12" status: "pending" accountRepresentativeID: "dabit" customerID: "jennifer_thomas" productID: "yeezyboost" }) { id customerID accountRepresentativeID amount date customerID productID }}1. 従業員IDで従業員の詳細を検索
これは従業員IDを使用して従業員モデルをクエリすることで簡単に実行できます。@primaryKeyまたは@indexを明示的に指定する必要はありません。
query getEmployee($id: ID!) { getEmployee(id: $id) { id name phoneNumber startDate jobTitle }}2. 従業員名で従業員の詳細をクエリ
EmployeeタイプのbyName @indexは、このアクセスパターンを実現します。これにより、内部でインデックスが作成され、nameフィールドと照合するためのクエリが使用されます。次のクエリを使用できます。
query employeeByName($name: String!) { employeeByName(name: $name) { items { id name phoneNumber startDate jobTitle } }}3. 従業員の電話番号を検索
前述のクエリのいずれかを使用して、従業員の電話番号を検索できます。ただし、ID名またはこうした情報が必要です。
4. 顧客の電話番号を検索
Customerモデルで上記と同様のクエリを実行すると、顧客の電話番号が取得できます。
query getCustomer($customerID: ID!) { getCustomer(id: $customerID) { phoneNumber }}5. 指定された日付範囲内で特定の顧客の注文を取得
顧客のすべての注文をクエリできる1対多の関係があります。
この関係は、OrderモデルのbyCustomerByDateインデックス名を持つ@indexにより作成され、Customerモデルのordersフィールドの@hasMany関係によりクエリされます。
日付付きのソートキーが使用されます。つまり、GraphQLリゾルバーはBetweenなどの述語を使用して、データベース内のすべてのレコードをスキャンしてフィルタリングするのではなく、日付範囲を効率的に検索できます。
日付範囲内で顧客に対する注文を取得するために必要なクエリは次のとおりです。
query getCustomerWithOrdersByDate($customerID: ID!) { getCustomer(id: $customerID) { ordersByDate(date: { between: [ "2018-01-22", "2020-10-11" ] }) { items { id amount productID } } }}6. 指定された日付範囲内のすべてのオープン注文をすべての顧客全体で表示
byCustomerByStatusByDate @indexを使用すると、このアクセスパターン用のクエリを実行できます。
この例では、statusとdateの複合ソートキー(2つ以上のキーの組み合わせ)が使用されます。つまり、これら2つのフィールド(statusとdate)を連結してデータベース内のレコードの一意の識別子が作成され、GraphQLリゾルバーはbetweenまたはcontainsなどの述語を使用して、データベース内のすべてのレコードをスキャンしてフィルタリングするのではなく、一意の識別子内の一致を効率的に検索できます。
query listCustomersWithOrdersByStatusDate { listCustomers { items { ordersByStatusDate(statusDate: { between: [ { status: "pending", date: "2018-01-22" }, { status: "pending", date: "2020-10-11" } ]}) { items { id amount date } } } }}7. 最近採用されたすべての従業員を表示
Employeeモデルに@index(name: "newHire", fields: ["newHire", "id"])があると、従業員が最近採用されたかどうかでクエリできます。
query employeesNewHire { employeesNewHire(newHire: "true") { items { id name phoneNumber startDate jobTitle } }}employeesNewHireByStartDateクエリを使用することで、開始日を返して結果を取得することもできます。
query employeesNewHireByDate { employeesNewHireByStartDate(newHire: "true") { items { id name phoneNumber startDate jobTitle } }}8. 特定のウェアハウスで働いているすべての従業員を検索
これは、ウェアハウスから従業員への1対多の関係が必要です。Warehouseモデルの@hasMany関係から見ることができるように、この関係はEmployeeモデルのbyWarehouseインデックスを使用しています。関連するクエリは次のようになります。
query getWarehouse($warehouseID: ID!) { getWarehouse(id: $warehouseID) { id employees{ items { id name startDate phoneNumber jobTitle } } }}9. 特定の製品に関して注文されているすべてのアイテムを取得
このアクセスパターンでは、製品から注文への1対多の関係を使用します。このクエリを使用して、特定の製品のすべての注文を取得できます。
query getProductOrders($productID: ID!) { getProduct(id: $productID) { id orders { items { id status amount date } } }}10. すべてのウェアハウスで特定の製品の現在の在庫を取得
すべてのウェアハウスで製品の在庫を取得するために必要なクエリは次のとおりです。
query getProductInventoryInfo($productID: ID!) { getProduct(id: $productID) { id inventories { items { warehouseID inventoryAmount } } }}11. 営業担当者別の顧客を取得
これは営業担当者と顧客の間にある多対多の関係を使用します。
必要なクエリは次のようになります。
query getCustomersForAccountRepresentative($representativeId: ID!) { getAccountRepresentative(id: $representativeId) { customers { items { id name phoneNumber } } }}12. 営業担当者と日付別の注文を取得
AccountRepresentativeモデルで見ることができるように、この関係はOrderモデルのbyRepresentativebyDateフィールドを使用して必要な接続を作成しています。必要なクエリは次のようになります。
query getOrdersForAccountRepresentative($representativeId: ID!) { getAccountRepresentative(id: $representativeId) { id orders(date: { between: [ "2010-01-22", "2020-10-11" ] }) { items { id status amount date } } }}13. 特定の製品に関して注文されているすべてのアイテムを取得
これは#9と同じです。
14. 指定されたジョブタイトルを持つすべての従業員を取得
byTitle @indexを使用すると、このアクセスパターンは簡単になります。
query employeesByJobTitle { employeesByJobTitle(jobTitle: "Manager") { items { id name phoneNumber jobTitle } }}15. 製品とウェアハウス別に在庫を取得
ここで、在庫を別のモデルに保持することは特に有用です。このモデルは独自のパーティションキーとソートキーを持つことができるため、在庫自体がこのアクセスパターン用に必要とされるようにクエリできます。
このモデルのクエリは次のようになります。
query inventoryByProductAndWarehouse($productID: ID!, $warehouseID: ID!) { getInventory(productID: $productID, warehouseID: $warehouseID) { productID warehouseID inventoryAmount }}byWarehouseIDキーで作成されたitemsByWarehouseIDクエリを使用して、個々のウェアハウスのすべての在庫を取得することもできます。
query byWarehouseId($warehouseID: ID!) { itemsByWarehouseID(warehouseID: $warehouseID) { items { inventoryAmount productID } }}16. 総製品在庫を取得
これをどのように行うかはユースケースによって異なります。すべてのウェアハウスのすべての在庫リストが必要な場合は、Inventoryモデルでリスト在庫を実行することができます。
query listInventorys { listInventorys { items { productID warehouseID inventoryAmount } }}17. 注文総額と営業期間でランク付けされた営業担当者を取得
営業期間は日付範囲、またはおそらく月または週でもあります。したがって、営業期間を文字列として設定し、salesPeriodとorderTotalの組み合わせを使用してクエリできます。また、sortDirectionを設定して、最大から最小までの戻り値を取得することもできます。
query repsByPeriodAndTotal { repsByPeriodAndTotal( sortDirection: DESC, salesPeriod: "January 2019", orderTotal: { ge: 1000 }) { items { id orderTotal } }}