Shopping Mall directory
Let’s look at the needs of application used to manage Shopping Mall properties. The application assists employees in the day-to-day operations of multiple Shopping Malls.
Requirements
- As a Maintenance Worker, I need to know which stores are currently in each Mall down to the Building they are located.
- As a Helpdesk Employee, I need to locate related stores in Mall locations by Store Category.
- As a Property Manager, I need to identify upcoming leases in need of renewal.
Example Setup
Example Setup
Table Definition
{ "TableName": "electro", "KeySchema": [ { "AttributeName": "pk", "KeyType": "HASH" }, { "AttributeName": "sk", "KeyType": "RANGE" } ], "AttributeDefinitions": [ { "AttributeName": "pk", "AttributeType": "S" }, { "AttributeName": "sk", "AttributeType": "S" }, { "AttributeName": "gsi1pk", "AttributeType": "S" }, { "AttributeName": "gsi1sk", "AttributeType": "S" } ], "GlobalSecondaryIndexes": [ { "IndexName": "gsi1pk-gsi1sk-index", "KeySchema": [ { "AttributeName": "gsi1pk", "KeyType": "HASH" }, { "AttributeName": "gsi1sk", "KeyType": "RANGE" } ], "Projection": { "ProjectionType": "ALL" } }, { "IndexName": "gsi2pk-gsi2sk-index", "KeySchema": [ { "AttributeName": "gsi2pk", "KeyType": "HASH" }, { "AttributeName": "gsi2sk", "KeyType": "RANGE" } ], "Projection": { "ProjectionType": "ALL" } } ], "BillingMode": "PAY_PER_REQUEST" }
(Example code on this page that references the entityExample Entity
import DynamoDB from "aws-sdk/clients/dynamodb"; import { Entity } from "electrodb"; const client = new DynamoDB.DocumentClient(); const table = "electro"; const StoreLocations = new Entity( { model: { service: "MallStoreDirectory", entity: "MallStore", version: "1", }, attributes: { cityId: { type: "string", required: true, }, mallId: { type: "string", required: true, }, storeId: { type: "string", required: true, }, buildingId: { type: "string", required: true, }, unitId: { type: "string", required: true, }, category: { type: [ "spite store", "food/coffee", "food/meal", "clothing", "electronics", "department", "misc", ], required: true, }, leaseEndDate: { type: "string", required: true, }, rent: { type: "string", required: true, validate: /^(\d+\.\d{2})$/, }, discount: { type: "string", required: false, default: "0.00", validate: /^(\d+\.\d{2})$/, }, tenants: { type: "set", items: "string", }, warnings: { type: "number", default: 0, }, deposit: { type: "number", }, contact: { type: "set", items: "string", }, rentalAgreement: { type: "list", items: { type: "map", properties: { type: { type: "string", }, detail: { type: "string", }, }, }, }, petFee: { type: "number", }, fees: { type: "number", }, tags: { type: "set", items: "string", }, }, indexes: { stores: { pk: { field: "pk", composite: ["cityId", "mallId"], }, sk: { field: "sk", composite: ["buildingId", "storeId"], }, }, units: { index: "gsi1pk-gsi1sk-index", pk: { field: "gsi1pk", composite: ["mallId"], }, sk: { field: "gsi1sk", composite: ["buildingId", "unitId"], }, }, leases: { index: "gsi2pk-gsi2sk-index", pk: { field: "gsi2pk", composite: ["storeId"], }, sk: { field: "gsi2sk", composite: ["leaseEndDate"], }, }, }, }, { table, client }, );
StoreLocations
uses the following Entity and Table Definition found below)
Mutations
Add a new Store to the Mall
await StoreLocations.create({
mallId: "EastPointe",
storeId: "LatteLarrys",
buildingId: "BuildingA1",
unitId: "B47",
category: "spite store",
leaseEndDate: "2020-02-29",
rent: "5000.00",
}).go();
Returns the following:
{
"data": {
"mallId": "EastPointe",
"storeId": "LatteLarrys",
"buildingId": "BuildingA1",
"unitId": "B47",
"category": "spite store",
"leaseEndDate": "2020-02-29",
"rent": "5000.00",
"discount": "0.00"
}
}
Change the Stores Lease Date
When updating a record, you must include all Composite Attributes associated with the table’s primary PK and SK.
let storeId = "LatteLarrys";
let mallId = "EastPointe";
let buildingId = "BuildingA1";
let unitId = "B47";
await StoreLocations.patch({ storeId, mallId, buildingId, unitId })
.set({ leaseEndDate: "2021-02-28" })
.go();
Returns the following:
{
"data": {
"leaseEndDate": "2021-02-28"
}
}
Retrieve a specific Store in a Mall
When retrieving a specific record, you must include all Composite Attributes associated with the table’s primary PK and SK.
let storeId = "LatteLarrys";
let mallId = "EastPointe";
let buildingId = "BuildingA1";
let unitId = "B47";
await StoreLocations.get({ storeId, mallId, buildingId, unitId }).go();
Returns the following:
{
"data": {
"mallId": "EastPointe",
"storeId": "LatteLarrys",
"buildingId": "BuildingA1",
"unitId": "B47",
"category": "spite store",
"leaseEndDate": "2021-02-28",
"rent": "5000.00",
"discount": "0.00"
}
}
Remove a Store location from the Mall
When removing a specific record, you must include all Composite Attributes associated with the table’s primary PK and SK.
let storeId = "LatteLarrys";
let mallId = "EastPointe";
let buildingId = "BuildingA1";
let unitId = "B47";
let storeId = "LatteLarrys";
await StoreLocations.delete({ storeId, mallId, buildingId, unitId }).go();
Returns the following:
{ "data": {} }
Queries
All Stores in a particular mall
Fulfilling Requirement #1.
let mallId = "EastPointe";
let stores = await StoreLocations.query.units({ mallId }).go();
All Stores in a particular mall building
Fulfilling Requirement #1.
let mallId = "EastPointe";
let buildingId = "BuildingA1";
let stores = await StoreLocations.query.units({ mallId, buildingId }).go();
Find the store located in unit B47
Fulfilling Requirement #1.
let mallId = "EastPointe";
let buildingId = "BuildingA1";
let unitId = "B47";
let stores = await StoreLocations.query
.units({ mallId, buildingId, unitId })
.go();
Stores by Category at Mall
Fulfilling Requirement #2.
let mallId = "EastPointe";
let category = "food/coffee";
let stores = await StoreLocations.query
.units({ mallId })
.where((attr, op) => op.eq(attr.category, category))
.go();
Stores by upcoming lease
Fulfilling Requirement #3.
let storeId = "LatteLarrys";
let q2StartDate = "2020-04-01";
let stores = await StoreLocations.query
.leases({ storeId })
.lt({ leaseEndDate: q2StartDate })
.go();
Stores will renewals for Q4
Fulfilling Requirement #3.
let storeId = "LatteLarrys";
let q4StartDate = "2020-10-01";
let q4EndDate = "2020-12-31";
let stores = await StoreLocations.query
.leases({ storeId })
.between({ leaseEndDate: q4StartDate }, { leaseEndDate: q4EndDate })
.go();
Spite-stores with release renewals this year
Fulfilling Requirement #3.
let storeId = "LatteLarrys";
let yearStarDate = "2020-01-01";
let yearEndDate = "2020-12-31";
let storeId = "LatteLarrys";
let stores = await StoreLocations.query
.leases({ storeId })
.between({ leaseEndDate: yearStarDate }, { leaseEndDate: yearEndDate })
.where((attr, op) => op.eq(attr.category, "Spite Store"))
.go();
All Latte Larry’s in a particular mall building
let mallId = "EastPointe";
let buildingId = "BuildingA1";
let unitId = "B47";
let storeId = "LatteLarrys";
let stores = await StoreLocations.query
.units({ mallId, buildingId, storeId })
.go();