diff --git a/.env b/.env deleted file mode 100644 index 1bad08d..0000000 --- a/.env +++ /dev/null @@ -1,10 +0,0 @@ -# Project name -COMPOSE_PROJECT_NAME=fiware - -# Orion variables -ORION_PORT=1026 -ORION_VERSION=3.11.0 - -# MongoDB variables -MONGO_DB_PORT=27017 -MONGO_DB_VERSION=6.0 \ No newline at end of file diff --git a/.gitpod.yml b/.gitpod.yml deleted file mode 100644 index 6f048a1..0000000 --- a/.gitpod.yml +++ /dev/null @@ -1,21 +0,0 @@ -tasks: - - name: Pull Images - init: ./services create - -ports: - - name: Orion - description: Context Broker - port: 1026 - onOpen: notify - - name: Tutorial App - description: Web app displaying context data - port: 3000 - onOpen: open-preview - - name: Tutorial Devices - description: Dummy IoT Sensors over HTTP - port: 3001 - onOpen: ignore - - name: MongoDB - description: Database for Orion - port: 27017 - onOpen: ignore \ No newline at end of file diff --git a/FIWARE Entity Relationships.postman_collection.json b/FIWARE Entity Relationships.postman_collection.json deleted file mode 100644 index 2361ade..0000000 --- a/FIWARE Entity Relationships.postman_collection.json +++ /dev/null @@ -1,422 +0,0 @@ -{ - "info": { - "_postman_id": "05e4b8a2-b7fd-4689-afd4-efb71cc2f17e", - "name": "FIWARE Entity Relationships", - "description": "This tutorial builds on the data created in the previous [store finder example](http://fiware.github.io/tutorials.Getting-Started/) and creates and associates a series of related data entities to create a simple stock management system.\n\nThe `docker-compose` file for this tutorial can be found on GitHub: \n\n![GitHub](https://fiware.github.io/tutorials.Entity-Relationships/icon/GitHub-Mark-32px.png) [FIWARE 102: Batch Commands and Entity Relationships](https://github.com/Fiware/tutorials.Entity-Relationships)\n\n# Data Entities\n\nWithin the FIWARE platform, an entity represents the state of a physical or conceptural object which exists in the real world.\n\n## Entities within a stock management system\n\nFor a simple stock management system, we will only need four types of entity. The relationship between our entities is defined as shown:\n\n![](https://fiware.github.io/tutorials.Entity-Relationships/img/entities.png)\n\n* A **Store** is a real world bricks and mortar building. Stores would have properties such as:\n + A name of the store e.g. \"Checkpoint Markt\"\n + An address \"Friedrichstraße 44, 10969 Kreuzberg, Berlin\"\n + A phyiscal location e.g. *52.5075 N, 13.3903 E*\n* A **Shelf** is a real world device to hold objects which we wish to sell. Each shelf would have properties such as:\n + A name of the shelf e.g. \"Wall Unit\"\n + A phyiscal location e.g. *52.5075 N, 13.3903 E*\n + A maximum capacity\n + An association to the store in which the shelf is present\n* A **Product** is defined as something that we sell - it is conceptural object. Products would have properties such as:\n + A name of the product e.g. \"Melons\"\n + A price e.g. 13.99 Euros\n + A size e.g. Small\n* An **Inventory Item** is another conceptural entity, used to assocate products, stores, shelves and physical objects. It would have properties such as:\n + An assocation to the product being sold\n + An association to the store in which the product is being sold\n + An association to the shelf where the product is being displayed\n + A stock count of the quantity of the product available in the warehouse\n + A stock count of the quantity of the product available on the shelf\n\n\nAs you can see, each of the entities defined above contain some properties which are liable to change. A product could change its price, stock could be sold and the shelf count of stock could be reduced and so on.\n\n\n# Architecture\n\nThis application will only make use of one FIWARE component - the [Orion Context Broker](https://catalogue.fiware.org/enablers/publishsubscribe-context-broker-orion-context-broker). Usage of the Orion Context Broker is sufficient for an application to qualify as *“Powered by FIWARE”*.\n\nCurrently, the Orion Context Broker relies on open source [MongoDB](https://www.mongodb.com/) technology to keep persistence of the context data it holds. Therefore, the architecture will consist of two elements:\n\n* The Orion Context Broker server which will receive requests using NGSI\n* The underlying MongoDB database associated to the Orion Context Broker server\n\nSince all interactions between the two elements are initiated by HTTP requests, the entities can be containerized and run from exposed ports. \n\n![](https://fiware.github.io/tutorials.Entity-Relationships/img/architecture.png)\n\nThe necessary configuration information can be seen in the services section of the associated `docker-compose.yml` file:\n\n```yaml\n orion:\n image: quay.io/fiware/orion:latest\n hostname: orion\n container_name: orion\n depends_on:\n - context-db\n networks:\n - default\n expose:\n - \"1026\"\n ports:\n - \"1026:1026\"\n command: -dbhost context-db -logLevel DEBUG\n```\n\n```yaml\n context-db:\n image: mongo:3.6\n hostname: context-db\n container_name: context-db\n expose:\n - \"27017\"\n ports:\n - \"27017:27017\"\n networks:\n - default\n\n```\n\nBoth containers are residing on the same network - the Orion Context Broker is listening on Port `1026` \nand MongoDB is listening on the default port `271071`. Both containers are also exposing the same ports\nexternally - this is purely for the tutorial access - so that cUrl or Postman can access them without\nbeing part of the same network. The command line initialization should be self explanatory.\n\n# Prerequisites\n\n## Docker\n\nTo keep things simple both components will be run using [Docker](https://www.docker.com). **Docker** is a container technology which allows to different components isolated into their respective environments. \n\n* To install Docker on Windows follow the instructions [here](https://docs.docker.com/docker-for-windows/)\n* To install Docker on Mac follow the instructions [here](https://docs.docker.com/docker-for-mac/)\n* To install Docker on Linux follow the instructions [here](https://docs.docker.com/install/)\n\n**Docker Compose** is a tool for defining and running multi-container Docker applications. A [YAML file](https://raw.githubusercontent.com/Fiware/tutorials.Entity-Relationships/master/docker-compose.yml) is used configure the required\nservices for the application. This means all container sevices can be brought up in a single commmand. Docker Compose is installed by default as part of Docker for Windows and Docker for Mac, however Linux users will need to follow the instructions found [here](https://docs.docker.com/compose/install/)\n\n## Cygwin \n\nWe will start up our services using a simple bash script. Windows users should download [cygwin](www.cygwin.com) to provide a command line functionality similar to a Linux distribution on Windows. \n\n\n# Start Up\n\nAll services can be initialised from the command line by running the bash script provided within the repository:\n\n```bash\n./services start\n```", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "Re-create two Stores (optional)", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"actionType\": \"APPEND\",\n \"entities\": [\n {\n \"type\": \"Store\",\n \"id\": \"urn:ngsi-ld:Store:001\",\n \"address\": {\n \"type\": \"PostalAddress\",\n \"value\": {\n \"streetAddress\": \"Bornholmer Straße 65\",\n \"addressRegion\": \"Berlin\",\n \"addressLocality\": \"Prenzlauer Berg\",\n \"postalCode\": \"10439\"\n }\n },\n \"location\": {\n \"type\": \"geo:json\",\n \"value\": {\n \"type\": \"Point\",\n \"coordinates\": [13.3986, 52.5547]\n }\n },\n \"name\": {\n \"type\": \"Text\",\n \"value\": \"Bösebrücke Einkauf\"\n }\n },\n {\n \"type\": \"Store\",\n \"id\": \"urn:ngsi-ld:Store:002\",\n \"address\": {\n \"type\": \"PostalAddress\",\n \"value\": {\n \"streetAddress\": \"Friedrichstraße 44\",\n \"addressRegion\": \"Berlin\",\n \"addressLocality\": \"Kreuzberg\",\n \"postalCode\": \"10969\"\n }\n },\n \"location\": {\n \"type\": \"geo:json\",\n \"value\": {\n \"type\": \"Point\",\n \"coordinates\": [13.3903, 52.5075]\n }\n },\n \"name\": {\n \"type\": \"Text\",\n \"value\": \"Checkpoint Markt\"\n }\n }\n ]\n}" - }, - "url": { - "raw": "http://{{orion}}/v2/op/update", - "protocol": "http", - "host": [ - "{{orion}}" - ], - "path": [ - "v2", - "op", - "update" - ] - }, - "description": "This example uses the convenience batch processing endpoint to re-create the two **Store** entities from the previous tutorial.\n\nBatch processing uses the `/v2/op/update` endpoint with a payload with two attributes - `actionType=APPEND` means we will overwrite existing entities if they exist whereas the `entities` attribute holds an array of entities we wish to update.\n\nAs you can see each **Store** entity in the payload has been given a unique `id` (according to the NGSI-LD [specification](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.03.01_60/gs_cim009v010301p.pdf)) and assigned `type=Store`." - }, - "response": [] - }, - { - "name": "Create Four Products", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"actionType\":\"APPEND\",\n \"entities\":[\n {\n \"id\":\"urn:ngsi-ld:Product:001\", \"type\":\"Product\",\n \"name\":{\n \"type\":\"Text\", \"value\":\"Apples\\n },\n \"size\":{\n \"type\":\"Text\", \"value\": \"S\"\n },\n \"price\":{\n \"type\":\"Integer\", \"value\": 99\n }\n },\n {\n \"id\":\"urn:ngsi-ld:Product:002\", \"type\":\"Product\",\n \"name\":{\n \"type\":\"Text\", \"value\":\"Bananas\"\n },\n \"size\":{\n \"type\":\"Text\", \"value\": \"M\"\n },\n \"price\":{\n \"type\":\"Integer\", \"value\": 1099\n }\n },\n {\n \"id\":\"urn:ngsi-ld:Product:003\", \"type\":\"Product\",\n \"name\":{\n \"type\":\"Text\", \"value\":\"Coconuts\"\n },\n \"size\":{\n \"type\":\"Text\", \"value\": \"M\"\n },\n \"price\":{\n \"type\":\"Integer\", \"value\": 1499\n }\n },\n {\n \"id\":\"urn:ngsi-ld:Product:004\", \"type\":\"Product\",\n \"name\":{\n \"type\":\"Text\", \"value\":\"Melons\"\n },\n \"size\":{\n \"type\":\"Text\", \"value\": \"XL\"\n },\n \"price\":{\n \"type\":\"Integer\", \"value\": 5000\n }\n }\n ]\n}" - }, - "url": { - "raw": "http://{{orion}}/v2/op/update", - "protocol": "http", - "host": [ - "{{orion}}" - ], - "path": [ - "v2", - "op", - "update" - ] - }, - "description": "This example uses the convenience batch processing endpoint to create a series of available products.\n\nBatch processing uses the `/v2/op/update` endpoint with a payload with two attributes - `actionType=APPEND` means we will overwrite existing entities if they exist whereas the `entities` attribute holds an array of entities we wish to update.\n\nEach product has a unique `id` following the NGSI-LD [specification](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.03.01_60/gs_cim009v010301p.pdf) and has been assigned `type=Product`." - }, - "response": [] - }, - { - "name": "Create Five Shelf Units", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"actionType\":\"APPEND\",\n \"entities\":[\n {\n \"id\":\"urn:ngsi-ld:Shelf:unit001\", \"type\":\"Shelf\",\n \"location\":{\n \"type\":\"geo:json\", \"value\":{ \"type\":\"Point\",\"coordinates\":[13.3986112, 52.554699]}\n },\n \"name\":{\n \"type\":\"Text\", \"value\":\"Corner Unit\"\n },\n \"maxCapacity\":{\n \"type\":\"Integer\", \"value\":50\n }\n },\n {\n \"id\":\"urn:ngsi-ld:Shelf:unit002\", \"type\":\"Shelf\",\n \"location\":{\n \"type\":\"geo:json\",\"value\":{\"type\":\"Point\",\"coordinates\":[13.3987221, 52.5546640]}\n },\n \"name\":{\n \"type\":\"Text\", \"value\":\"Wall Unit 1\"\n },\n \"maxCapacity\":{\n \"type\":\"Integer\", \"value\":100\n }\n },\n {\n \"id\":\"urn:ngsi-ld:Shelf:unit003\", \"type\":\"Shelf\",\n \"location\":{\n \"type\":\"geo:json\", \"value\":{\"type\":\"Point\",\"coordinates\":[13.3987221, 52.5546640]}\n },\n \"name\":{\n \"type\":\"Text\", \"value\":\"Wall Unit 2\"\n },\n \"maxCapacity\":{\n \"type\":\"Integer\", \"value\":100\n }\n },\n {\n \"id\":\"urn:ngsi-ld:Shelf:unit004\", \"type\":\"Shelf\",\n \"location\":{\n \"type\":\"geo:json\", \"value\":{\"type\":\"Point\",\"coordinates\":[13.390311, 52.507522]}\n },\n \"name\":{\n \"type\":\"Text\", \"value\":\"Corner Unit\"\n },\n \"maxCapacity\":{\n \"type\":\"Integer\", \"value\":50\n }\n },\n {\n \"id\":\"urn:ngsi-ld:Shelf:unit005\", \"type\":\"Shelf\",\n \"location\":{\n \"type\":\"geo:json\",\"value\":{\"type\":\"Point\",\"coordinates\":[13.390309, 52.50751]}\n },\n \"name\":{\n \"type\":\"Text\", \"value\":\"Long Wall Unit\"\n },\n \"maxCapacity\":{\n \"type\":\"Integer\", \"value\":200\n }\n }\n ]\n}" - }, - "url": { - "raw": "http://{{orion}}/v2/op/update", - "protocol": "http", - "host": [ - "{{orion}}" - ], - "path": [ - "v2", - "op", - "update" - ] - }, - "description": "This example uses the convenience batch processing endpoint to create the five shelf entities.\n\nBatch processing uses the `/v2/op/update` endpoint with a payload with two attributes - `actionType=APPEND` means we will overwrite existing entities if they exist whereas the `entities` attribute holds an array of entities we wish to update.\n\nTo differenciate **Shelf** Entities from **Store** Entities, each shelf has been assigned `type=Shelf`. The `id` of each **Shelf** Entity follows the NGSI-LD [specification](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.03.01_60/gs_cim009v010301p.pdf) and is therefore unique.\n\nReal-world properties such as `name` and `location` have been addded as properties to each shelf." - }, - "response": [] - }, - { - "name": "Obtain Shelf Information", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://{{orion}}/v2/entities/urn:ngsi-ld:Shelf:unit001/?options=keyValues", - "protocol": "http", - "host": [ - "{{orion}}" - ], - "path": [ - "v2", - "entities", - "urn:ngsi-ld:Shelf:unit001", - "" - ], - "query": [ - { - "key": "type", - "value": "Shelf", - "description": "Entity type", - "disabled": true - }, - { - "key": "options", - "value": "keyValues", - "description": "* `keyValues` option in order to get a more compact and brief representation, including just attribute values\n* `values` option combined with a list of attribute values `attrs` for an ordered list of attributes only" - } - ] - }, - "description": "This example returns the context data of the *Shelf* entity with the `id=urn:ngsi-ld:Shelf:unit001`.\n\nThere are currently three additional property attributes present `location`, `maxCapacity` and `name`" - }, - "response": [] - }, - { - "name": "Adding a Foreign Key Relationship", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"actionType\":\"APPEND\",\n \"entities\":[\n {\n \"id\":\"urn:ngsi-ld:Shelf:unit001\", \"type\":\"Shelf\",\n \"refStore\": { \n \"type\": \"Relationship\",\n \"value\": \"urn:ngsi-ld:Store:001\"\n }\n },\n {\n \"id\":\"urn:ngsi-ld:Shelf:unit002\", \"type\":\"Shelf\",\n \"refStore\": { \n \"type\": \"Relationship\",\n \"value\": \"urn:ngsi-ld:Store:001\"\n }\n },\n {\n \"id\":\"urn:ngsi-ld:Shelf:unit003\", \"type\":\"Shelf\",\n \"refStore\": { \n \"type\": \"Relationship\",\n \"value\": \"urn:ngsi-ld:Store:001\"\n }\n },\n {\n \"id\":\"urn:ngsi-ld:Shelf:unit004\", \"type\":\"Shelf\",\n \"refStore\": { \n \"type\": \"Relationship\",\n \"value\": \"urn:ngsi-ld:Store:002\"\n }\n },\n {\n \"id\":\"urn:ngsi-ld:Shelf:unit005\", \"type\":\"Shelf\",\n \"refStore\": { \n \"type\": \"Relationship\",\n \"value\": \"urn:ngsi-ld:Store:002\"\n }\n }\n ]\n}" - }, - "url": { - "raw": "http://{{orion}}/v2/op/update", - "protocol": "http", - "host": [ - "{{orion}}" - ], - "path": [ - "v2", - "op", - "update" - ] - }, - "description": "This example uses batch processing to amend the existing the **Shelf** entities to add a `refStore` relationship to each shelf. According to the FIWARE Data Modelling Guidelines on [linked data](http://fiware-datamodels.readthedocs.io/en/latest/guidelines/index.html#modelling-linked-data), when an entity attribute is used as a link to other entities it should be named with the prefix `ref` plus the name of the target (linked) entity type. \n\nBatch processing uses the `/v2/op/update` endpoint with a payload with two attributes - `actionType=APPEND` means we will overwrite existing entities if they exist whereas the `entities` attribute holds an array of entities we wish to update.\n\nThe value corresponds to a URN associated to an existing **Store** entity within the context." - }, - "response": [] - }, - { - "name": "Obtain Updated Shelf Information", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://{{orion}}/v2/entities/urn:ngsi-ld:Shelf:unit001/?options=keyValues", - "protocol": "http", - "host": [ - "{{orion}}" - ], - "path": [ - "v2", - "entities", - "urn:ngsi-ld:Shelf:unit001", - "" - ], - "query": [ - { - "key": "type", - "value": "Shelf", - "description": "Entity type", - "disabled": true - }, - { - "key": "options", - "value": "keyValues", - "description": "* `keyValues` option in order to get a more compact and brief representation, including just attribute values\n* `values` option combined with a list of attribute values `attrs` for an ordered list of attributes only" - } - ] - }, - "description": "This example returns the context data of the `Shelf` entity with the `id=urn:ngsi-ld:Shelf:unit001`.\n\nThe response now includes a new relationship property `refStore`, which has been added in the previous step." - }, - "response": [] - }, - { - "name": "Obtain a Foreign Key URN", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://{{orion}}/v2/entities/urn:ngsi-ld:Shelf:unit001/?options=values&attrs=refStore", - "protocol": "http", - "host": [ - "{{orion}}" - ], - "path": [ - "v2", - "entities", - "urn:ngsi-ld:Shelf:unit001", - "" - ], - "query": [ - { - "key": "type", - "value": "Shelf", - "description": "Entity type", - "disabled": true - }, - { - "key": "options", - "value": "values", - "description": "* `keyValues` option in order to get a more compact and brief representation, including just attribute values\n* `values` option combined with a list of attribute values `attrs` for an ordered list of attributes only" - }, - { - "key": "attrs", - "value": "refStore", - "description": "Ordered list of attribute names to display" - } - ] - }, - "description": "This example returns the `refStore` value associated with a given `Shelf` unit. \n\nIf the `id` and `type` of a data entity are known, a specific field can be requested by combining the `options=values` parameter and the `attrs` parameter. \n\nThe URN returned has a standard format: `urn:ngsi-ld::`, which has been used as the `id` of the **Store** entity itself (based on the NGSI-LD [specification](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.03.01_60/gs_cim009v010301p.pdf)), therefore it is a simple matter to request more information about the linked store by making a query to the `/entities` endpoint.\n\n```\nhttp://{{orion}}/v2/entities/urn:ngsi-ld:Store:001?options=keyValues\n```" - }, - "response": [] - }, - { - "name": "Obtain all Shelf Units found within a Store", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://{{orion}}/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&type=Shelf&options=values&attrs=name", - "protocol": "http", - "host": [ - "{{orion}}" - ], - "path": [ - "v2", - "entities", - "" - ], - "query": [ - { - "key": "q", - "value": "refStore==urn:ngsi-ld:Store:001" - }, - { - "key": "type", - "value": "Shelf", - "description": "Entity type" - }, - { - "key": "options", - "value": "values", - "description": "* `keyValues` option in order to get a more compact and brief representation, including just attribute values\n* `values` option combined with a list of attribute values `attrs` for an ordered list of attributes only" - }, - { - "key": "attrs", - "value": "name", - "description": "Ordered list of attribute names to display" - } - ] - }, - "description": "This example returns the `name` of all `Shelf` entities associated with the `shop1`.\n\nThe value of the query parameter `q` holds a URN of the form `urn:ngsi-ld::` which corresponds to the the Relationship URN in order to filter the information returned." - }, - "response": [] - }, - { - "name": "Putting a Product onto a shelf", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"id\": \"urn:ngsi-ld:InventoryItem:001\", \"type\": \"InventoryItem\",\n \"refStore\": { \n \"type\": \"Relationship\",\n \"value\": \"urn:ngsi-ld:Store:001\"\n },\n \"refShelf\": { \n \"type\": \"Relationship\",\n \"value\": \"urn:ngsi-ld:Shelf:unit001\"\n },\n \"refProduct\": { \n \"type\": \"Relationship\",\n \"value\": \"urn:ngsi-ld:Product:001\"\n },\n \"stockCount\":{\n \"type\":\"Integer\", \"value\": 10000\n },\n \"shelfCount\":{\n \"type\":\"Integer\", \"value\": 50\n }\n}" - }, - "url": { - "raw": "http://{{orion}}/v2/entities/", - "protocol": "http", - "host": [ - "{{orion}}" - ], - "path": [ - "v2", - "entities", - "" - ] - }, - "description": "The **InventoryItem** entity exists to associate data from other entities. It has a foreign key relationship to the **Store**, **Shelf** and **Product** entities and therefore requires relationship attributes called `refStore`, `refShelf` and `refProduct`.\n\nAssigning a product to a shelf is simply a create an entity holding the relationship information and any other additional properties (such as `stockCount` and `shelfCount`)." - }, - "response": [] - }, - { - "name": "Find all stores in which a product is sold", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://{{orion}}/v2/entities/?q=refProduct==urn:ngsi-ld:Product:001&options=values&attrs=refStore&type=InventoryItem", - "protocol": "http", - "host": [ - "{{orion}}" - ], - "path": [ - "v2", - "entities", - "" - ], - "query": [ - { - "key": "q", - "value": "refProduct==urn:ngsi-ld:Product:001" - }, - { - "key": "options", - "value": "values", - "description": "* `keyValues` option in order to get a more compact and brief representation, including just attribute values\n* `values` option combined with a list of attribute values `attrs` for an ordered list of attributes only\n" - }, - { - "key": "attrs", - "value": "refStore", - "description": "Ordered list of attribute names to display" - }, - { - "key": "type", - "value": "InventoryItem", - "description": "Entity type" - } - ] - }, - "description": "This example returns the URN of all stores in which the product `id=urn:ngsi-ld:Product:001` is sold. The URN returned has a standard format: `urn:ngsi-ld::`.\n\nBecause we have based the `id` of the **Store** entity on the NGSI-LD [specification](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.03.01_60/gs_cim009v010301p.pdf)), therefore it is a simple matter to request more information about the linked store by making a query to the `/entities` endpoint.\n\n```\nhttp://{{orion}}/v2/entities/urn:ngsi-ld:Store:001?options=keyValues\n```\n\nSince there is no direct relationship between product and store, a query must be made to find all entities which have both `refProduct` and `refStore` attributes.\n\nIn our current context the `type` parameter is optional since only one type of entity contains the fields requested in the request" - }, - "response": [] - }, - { - "name": "Find all Entities related to a Store", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://{{orion}}/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&options=count&attrs=type", - "protocol": "http", - "host": [ - "{{orion}}" - ], - "path": [ - "v2", - "entities", - "" - ], - "query": [ - { - "key": "q", - "value": "refStore==urn:ngsi-ld:Store:001" - }, - { - "key": "options", - "value": "count", - "description": "* `keyValues` option in order to get a more compact and brief representation, including just attribute values\n* `values` option combined with a list of attribute values `attrs` for an ordered list of attributes only" - }, - { - "key": "attrs", - "value": "type", - "description": "Ordered list of attribute names to display" - } - ] - }, - "description": "This example returns the key of all entities directly associated with the `urn:ngsi-ld:Store:001`.\n\nThe response lists a series of Shelf and InventoryItem entities - there are no products since there is no direct relationship between product and store.\n\nIf this request returns an empty array, the entity has no associates." - }, - "response": [] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "id": "f1d42f27-1cae-4144-b06e-237fad09b51b", - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "id": "028325fa-d62b-4d7a-afbf-5b138040015a", - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ], - "variable": [ - { - "id": "73b7c194-97af-4388-81ee-6dce0839c507", - "key": "orion", - "value": "localhost:1026", - "type": "string", - "description": "" - } - ] -} diff --git a/README.es.md b/README.es.md deleted file mode 100644 index 5edd483..0000000 --- a/README.es.md +++ /dev/null @@ -1,647 +0,0 @@ -[![FIWARE Banner](https://fiware.github.io/tutorials.Entity-Relationships/img/fiware.png)](https://www.fiware.org/developers) -[![NGSI v2](https://img.shields.io/badge/NGSI-v2-5dc0cf.svg)](https://fiware-ges.github.io/orion/api/v2/stable/) - -[![FIWARE Core Context Management](https://nexus.lab.fiware.org/repository/raw/public/badges/chapters/core.svg)](https://github.com/FIWARE/catalogue/blob/master/core/README.md) -[![License: MIT](https://img.shields.io/github/license/fiware/tutorials.Entity-Relationships.svg)](https://opensource.org/licenses/MIT) -[![Support badge](https://img.shields.io/badge/tag-fiware-orange.svg?logo=stackoverflow)](https://stackoverflow.com/questions/tagged/fiware) -
-[![Documentation](https://img.shields.io/readthedocs/fiware-tutorials.svg)](https://fiware-tutorials.rtfd.io) - -Este tutorial enseña a los usuarios de FIWARE acerca de los comandos por lotes (batch processing) y las relaciones de entidad. El tutorial se basa en los datos creados en el ejemplo anterior [buscador de tiendas](https://github.com/FIWARE/tutorials.Getting-Started/blob/master/README.es.md), agrega y -asocia una serie de entidades de datos relacionadas para crear un sistema sencillo de gestión inventarios. - -A lo largo de este tutorial se utilizan comandos [cUrl](https://ec.haxx.se/), pero también está disponible como -[documentación de Postman](https://fiware.github.io/tutorials.Entity-Relationships/). - -[![Ejecutar en Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/0671934f64958d3200b3) -[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/FIWARE/tutorials.Entity-Relationships/tree/NGSI-v2) - -- このチュートリアルは[日本語](https://github.com/FIWARE/tutorials.Entity-Relationships/blob/master/README.ja.md)でも - ご覧いただけます。
🇪n This tutorial is also available in [english](README.md) - -## Contenido - -
-Detalle - -- [Comprensión de entidades y relaciones](#comprension-de-entidades-y-relaciones) - - [Entidades en un sistema de gestión de inventarios](#entidades-en-un-sistema-de-gestion-de-inventarios) -- [Arquitectura](#arquitectura) -- [Pre requisitos](#pre-requisitos) - - [Docker y Docker Compose](#docker-y-docker-compose) - - [Cygwin para Windows](#cygwin-para-windows) -- [Inicio](#inicio) -- [Creación y asociación de entidades de datos](#creacion-y-asociacion-de-entidades-de-datos) - - [Creación de varias entidades a la vez](#creacion-de-varias-entidades-a-la-vez) - - [Creación de una Relación de uno-a-muchos](#creacion-de-una-relacion-de-uno-a-muchos) - - [Lectura de una Relación de Clave Foránea](#lectura-de-una-relacion-de-clave-foranea) - - [Lectura desde la Entidad Hijo a la Entidad Padre](#lectura-desde-la-entidad-hijo-a-la-entidad-padre) - - [Lectura desde la Entidad Padre a la Entidad Hijo](#lectura-desde-la-entidad-padre-a-la-entidad-hijo) - - [Creando Relaciones de muchos-a-muchos](#creando-relaciones-de-muchos-a-muchos) - - [Leyendo desde una tabla puente](#leyendo-desde-una-tabla-puente) - - [Integridad de los datos](#Integridad-de-los-datos) -- [Próximos pasos](#proximos-pasos) - -
- -# Comprensión de entidades y relaciones - -En la plataforma FIWARE, el contexto de una entidad representa el estado de un objeto físico o conceptual que -existe en el mundo real. - -## Entidades en un sistema de gestión de inventarios - -Para un sistema simple de gestión de inventarios, sólo necesitaremos cuatro tipos de entidades. La relación entre nuestras entidades se define a continuación: - -![](https://fiware.github.io/tutorials.Entity-Relationships/img/entities.png) - -- Una tienda (store) es un edificio concreto (de ladrillos) del mundo real. Entidades **Store** pueden tener propiedades como: - - Nombre de la tienda, por ejemplo: "Checkpoint Markt" - - Una dirección, por ejemplo: "Friedrichstraße 44, 10969 Kreuzberg, Berlin" - - Una ubicación física, por ejemplo: _52.5075 N, 13.3903 E_ -- Un estante (shelf) es una entidad del mundo real para guardar los objetos que queremos vender. Cada entidad **Shelf** puede tener propiedades como: - - Nombre del estante, por ejemplo: "Wall Unit" - - Una ubicación física, por ejemplo: _52.5075 N, 13.3903 E_ - - Una capacidad máxima - - Una asociación a la store (tienda) a la que pertenece -- Un producto (product) es algo que se desea vender - es un objeto conceptual. Entidades **Product** pueden tener propiedades como: - - Nombre del producto, por ejemplo "Melons" - - Su precio, por ejemplo: 13.99 Euros - - Un tamaño, por ejemplo: Pequeño -- Un artículo de inventario (inventory) es otra entidad conceptual, utilizada para asociar productos, tiendas, estantes y objetos físicos. - Entidades **Inventory Item** pueden tener propiedades como: - - Una asociación con el producto que se vende - - Una asociación a la tienda en la que se vende el producto - - Una asociación con el estante donde se exhibe el producto - - Un recuento de la cantidad de producto disponible en el almacén - - Un recuento de la cantidad de producto disponible en el estante - -Como puede ver, cada una de las entidades definidas anteriormente contienen propiedades que pueden cambiar. Un producto podría -cambiar su precio, se podrían vender las existencias y reducir el número de existencias en las estanterías, etc. - -> **Nota** este tutorial utiliza el siguiente estilo tipográfico: -> -> - Los tipos de entidades se escriben con **texto en negrita** -> - Los atributos de los datos se escriben en `texto de espaciado fijo` -> - Los artículos en el mundo real es escriben en texto simple, sin estilo -> -> Por lo tanto, una tienda en el mundo real está representada en los datos de contexto por una entidad **Store**, y un estante del mundo -> real encontrado en una tienda está representado por una entidad **Shelf** con un atributo `refStore`. - -# Arquitectura - -Esta aplicación sólo hará uso de un componente FIWARE - el -[Orion Context Broker](https://fiware-orion.readthedocs.io/en/latest/) (Corredor de Contexto de Orión). El uso del Orion Context Broker es suficiente -para una aplicación para calificar como _"Powered by FIWARE"_. - -Actualmente, el Orion Context Broker depende de la tecnología de código abierto [MongoDB](https://www.mongodb.com/) para mantener -la persistencia de los datos de contexto que contiene. Por lo tanto, la arquitectura consistirá en dos elementos: - -- El [Orion Context Broker](https://fiware-orion.readthedocs.io/en/latest/) recibirá las solicitudes utilizando - [NGSI-v2](https://fiware.github.io/specifications/OpenAPI/ngsiv2) -- La base de datos subyacente [MongoDB](https://www.mongodb.com/): - - Utilizada por el Orion Context Broker para guardar información de datos de contexto como entidades de datos, suscripciones e inscripciones - -Dado que todas las interacciones entre los dos elementos se inician mediante solicitudes HTTP, las entidades pueden ser aisladas en contenedores y corridas desde puertos expuestos. - -![](https://fiware.github.io/tutorials.Entity-Relationships/img/architecture.png) - -La información de configuración necesaria se puede ver en la sección de servicios del archivo asociado `docker-compose.yml`: - -```yaml -orion: - image: quay.io/fiware/orion:latest - hostname: orion - container_name: fiware-orion - depends_on: - - mongo-db - networks: - - default - expose: - - "1026" - ports: - - "1026:1026" - command: -dbhost mongo-db -logLevel DEBUG -``` - -```yaml -mongo-db: - image: mongo:4.2 - hostname: mongo-db - container_name: db-mongo - expose: - - "27017" - ports: - - "27017:27017" - networks: - - default - -``` - -Ambos contenedores residen en la misma red - Orion Context Broker escucha en el puerto `1026` y MongoDB lo hace por defecto en el puerto `27017`. Ambos contenedores también están exponiendo los mismos puertos externamente - esto es puramente para -el acceso al tutorial - para que cUrl o Postman puedan acceder a ellos sin ser parte de la misma red. -La inicialización por línea de comandos es autoexplicativa. - -# Pre requisitos - -## Docker y Docker Compose - -Para mantener las cosas simples ambos componentes se ejecutarán usando [Docker](https://www.docker.com). **Docker** es una tecnología de contenedor que permite aislar diferentes componentes en sus respectivos entornos. -- Para instalar Docker en Windows siga las instrucciones [aquí](https://docs.docker.com/docker-for-windows/) -- Para instalar Docker en Mac siga las instrucciones [aquí](https://docs.docker.com/docker-for-mac/) -- Para instalar Docker en Linux siga las instrucciones [aquí](https://docs.docker.com/install/) - -**Docker Compose** es una herramienta para definir y ejecutar aplicaciones Docker multi-contenedores. Un -[archivo YAML](https://raw.githubusercontent.com/Fiware/tutorials.Entity-Relationships/master/docker-compose.yml) se utiliza para configurar los servicios necesarios para la aplicación. Esto significa que todos los servicios de los contenedores pueden ser ejecutados en un solo comando. Docker Compose está instalado por defecto como parte de Docker para Windows y Docker para Mac, sin embargo los usuarios de Linux tendrán que seguir las instrucciones que se encuentran [aquí](https://docs.docker.com/compose/install/) - -Puede comprobar sus versiones actuales de **Docker** y **Docker Compose** usando los siguientes comandos: - -```console -docker-compose -v -docker version -``` - -Por favor, asegúrese de que esté usando la versión 18.03 o superior de Docker y la versión 1.21 o superior de Docker Compose y actualice si es necesario. - -## Cygwin para Windows - -Iniciaremos nuestros servicios usando un simple script de Bash. Los usuarios de Windows deben descargar [cygwin](http://www.cygwin.com/) -para proporcionar una funcionalidad de línea de comandos similar a la de una distribución de Linux en Windows. - -# Inicio - -Todos los servicios pueden ser inicializados desde la línea de comando ejecutando el script Bash proporcionado en el repositorio -[services](https://github.com/FIWARE/tutorials.Entity-Relationships/blob/NGSI-v2/services). Por favor, clone el repositorio y cree las imágenes necesarias ejecutando los comandos como se muestra: - -```console -git clone https://github.com/FIWARE/tutorials.Entity-Relationships.git -cd tutorials.Entity-Relationships -git checkout NGSI-v2 - -./services start -``` - -Este comando también importará datos iniciales del ejemplo anterior -[Tutorial del Buscador de Tiendas](https://github.com/FIWARE/tutorials.Getting-Started/blob/master/README.es.md). - - -> :information_source: **Nota:** Si quiere limpiar y empezar de nuevo puedes hacerlo con el siguiente comando: -> -> ```console -> ./services stop -> ``` - -# Creación y asociación de entidades de datos - -## Creación de varias entidades a la vez - -En el tutorial anterior, creamos cada entidad de **Store** individualmente. - -Vamos a crear cinco unidades de estantes al mismo tiempo. Esta solicitud utiliza el endpoint del procesamiento por lotes para crear cinco entidades de estantes. El procesamiento por lotes utiliza el endpoint "v2/op/update" con un payload con dos atributos - `actionType=APPEND` significa que sobrescribiremos las entidades existentes si existiesen, mientras que el atributo `entities` contiene un conjunto de entidades que deseamos actualizar. - -Para diferenciar las entidades **Shelf** de las entidades **Store**, a cada estante se le ha asignado "tipo=Shelf". Propiedades como "nombre" y "ubicación" han sido añadidas como propiedades a cada estante. - -#### 1️⃣ Solicitud: - -```console -curl -iX POST \ - 'http://localhost:1026/v2/op/update' \ - -H 'Content-Type: application/json' \ - -d '{ - "actionType":"APPEND", - "entities":[ - { - "id":"urn:ngsi-ld:Shelf:unit001", "type":"Shelf", - "location":{ - "type":"geo:json", "value":{ "type":"Point","coordinates":[13.3986112, 52.554699]} - }, - "name":{ - "type":"Text", "value":"Corner Unit" - }, - "maxCapacity":{ - "type":"Integer", "value":50 - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit002", "type":"Shelf", - "location":{ - "type":"geo:json","value":{"type":"Point","coordinates":[13.3987221, 52.5546640]} - }, - "name":{ - "type":"Text", "value":"Wall Unit 1" - }, - "maxCapacity":{ - "type":"Integer", "value":100 - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit003", "type":"Shelf", - "location":{ - "type":"geo:json", "value":{"type":"Point","coordinates":[13.3987221, 52.5546640]} - }, - "name":{ - "type":"Text", "value":"Wall Unit 2" - }, - "maxCapacity":{ - "type":"Integer", "value":100 - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit004", "type":"Shelf", - "location":{ - "type":"geo:json", "value":{"type":"Point","coordinates":[13.390311, 52.507522]} - }, - "name":{ - "type":"Text", "value":"Corner Unit" - }, - "maxCapacity":{ - "type":"Integer", "value":50 - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit005", "type":"Shelf", - "location":{ - "type":"geo:json","value":{"type":"Point","coordinates":[13.390309, 52.50751]} - }, - "name":{ - "type":"Text", "value":"Long Wall Unit" - }, - "maxCapacity":{ - "type":"Integer", "value":200 - } - } - ] -}' -``` - -De manera similar, podemos crear una serie de entidades **Product** utilizando el `type=Product`. - -#### 2️⃣ Solicitud: - -```console -curl -iX POST \ - 'http://localhost:1026/v2/op/update' \ - -H 'Content-Type: application/json' \ - -d '{ - "actionType":"APPEND", - "entities":[ - { - "id":"urn:ngsi-ld:Product:001", "type":"Product", - "name":{ - "type":"Text", "value":"Apples" - }, - "size":{ - "type":"Text", "value": "S" - }, - "price":{ - "type":"Integer", "value": 99 - } - }, - { - "id":"urn:ngsi-ld:Product:002", "type":"Product", - "name":{ - "type":"Text", "value":"Bananas" - }, - "size":{ - "type":"Text", "value": "M" - }, - "price":{ - "type":"Integer", "value": 1099 - } - }, - { - "id":"urn:ngsi-ld:Product:003", "type":"Product", - "name":{ - "type":"Text", "value":"Coconuts" - }, - "size":{ - "type":"Text", "value": "M" - }, - "price":{ - "type":"Integer", "value": 1499 - } - }, - { - "id":"urn:ngsi-ld:Product:004", "type":"Product", - "name":{ - "type":"Text", "value":"Melons" - }, - "size":{ - "type":"Text", "value": "XL" - }, - "price":{ - "type":"Integer", "value": 5000 - } - } - ] -}' -``` - -En ambos casos hemos codificado cada entidad `id` de acuerdo con la especificació -[NGSI-LD](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.08.01_60/gs_cim009v010801p.pdf) - la propuesta es que cada `id` es una URN y sigue un formato estándar: `urn:ngsi-ld::`.Esto significará que cada `id` en el sistema será único. - -La información de Shelf puede ser solicitada haciendo una petición GET en el endpoint `v2/entities`. Por ejemplo, para devolver los datos de contexto de la entidad **Shelf** con el `id=urn:ngsi-ld:Shelf:unit001`. - -#### 3️⃣ Solicitud: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/urn:ngsi-ld:Shelf:unit001/?type=Shelf&options=keyValues' -``` - -#### Respuesta: - -```json -{ - "id": "urn:ngsi-ld:Shelf:unit001", - "type": "Shelf", - "location": { - "type": "Point", - "coordinates": [13.3986112, 52.554699] - }, - "maxCapacity": 50, - "name": "Corner Unit" -} -``` - -Como puede ver, hay actualmente tres atributos de propiedad adicionales: `location`, `maxCapacity` y `name`. - -## Creación de una Relación de uno-a-muchos - -En bases de datos, las claves externas se utilizan a menudo para designar una relación de uno a muchos - por ejemplo, cada estante se encuentra en una sola tienda pero un almacén puede albergar muchos estantes. Para poder recordar esta información necesitamos añadir una -relación de asociación similar a una clave foránea. El procesamiento por lotes puede utilizarse de nuevo para modificar las -entidades **Shelf** para añadir un atributo `refStore` que mantiene la relación con cada tienda. De acuerdo con la guía de modelados de datos de FIWARE [datos vinculados](https://smartdatamodels.org/), cuando se utilice un atributo de entidad como vínculo con otras entidades, deberá nombrarse con el prefijo `ref`más el nombre del tipo de entidad de destino (vinculado). - -El valor del atributo `refStore` corresponde a una URN asociada a la propia entidad **Store**. - -La URN sigue un formato estándar: `urn:ngsi-ld::` - -#### 4️⃣ Solicitud: - -La siguiente solicitud asocia tres estantes a `urn:ngsi-ld:Store:001` y dos estantes a `urn:ngsi-ld:Store:002`. - -```console -curl -iX POST \ - 'http://localhost:1026/v2/op/update' \ - -H 'Content-Type: application/json' \ - -d '{ - "actionType":"APPEND", - "entities":[ - { - "id":"urn:ngsi-ld:Shelf:unit001", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:001" - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit002", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:001" - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit003", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:001" - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit004", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:002" - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit005", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:002" - } - } - ] -}' -``` - -Cuando la información del estante se solicita de nuevo, la respuesta ha cambiado e incluye una nueva propiedad `refStore`, añadida en el paso anterior. - -#### 5️⃣ Solicitud: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/urn:ngsi-ld:Shelf:unit001/?type=Shelf&options=keyValues' -``` - -#### Respuesta: - -La respuesta actualizada que incluye el atributo `refStore` se muestra a continuación: - -```json -{ - "id": "urn:ngsi-ld:Shelf:unit001", - "type": "Shelf", - "location": { - "type": "Point", - "coordinates": [13.3986112, 52.554699] - }, - "maxCapacity": 50, - "name": "Corner Unit", - "refStore": "urn:ngsi-ld:Store:001" -} -``` - -## Lectura de una Relación de Clave Foránea - -### Lectura desde la Entidad Hijo a la Entidad Padre - -También podemos hacer una solicitud para recuperar la información de la relación de atributos `refStore` de una entidad conocida `Shelf` usando el parámetro "options=values". - -#### 6️⃣ Solicitud: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/urn:ngsi-ld:Shelf:unit001/?type=Shelf&options=values&attrs=refStore' -``` - -#### Respuesta: - -```json -["urn:ngsi-ld:Store:001"] -``` - -Esto puede ser interpretado como "Estoy relacionado con la entidad **Store** con el `id=urn:ngsi-ld:Store:001`" - -### Lectura desde la Entidad Padre a la Entidad Hijo - -La lectura de un padre a un hijo puede hacerse usando el parámetro `options=count`. - -#### 7️⃣ Solicitud: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&options=count&attrs=type&type=Shelf' -``` - -Esta solicitud está pidiendo el `id` de todas las entidades de **Shelf** asociadas a la URN `urn:ngsi-ld:Store:001`, la respuesta es un arreglo JSON como se muestra. - -#### Respuesta: - -```json -[ - { - "id": "urn:ngsi-ld:Shelf:unit001", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:Shelf:unit002", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:Shelf:unit003", - "type": "Shelf" - } -] -``` - -En lenguaje coloquial, esto puede interpretarse como "Hay tres estantes en `urn:ngsi-ld:Store:001`". La petición puede ser alterada usando los parámetros `options=values` y `attrs` para devolver propiedades específicas de las entidades asociadas relevantes. Por ejemplo, la solicitud: - - -#### 8️⃣ Solicitud: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&type=Shelf&options=values&attrs=name' -``` - -Puede ser interpretada como una petición de _Dame los nombres de todos los estantes en `urn:ngsi-ld:Store:001`_. - -#### Respuesta: - -```json -[["Corner Unit"], ["Wall Unit 1"], ["Wall Unit 2"]] -``` - -## Creando Relaciones de muchos-a-muchos - -Tablas puente se utilizan a menudo para relacionar las relaciones de muchos con muchos. Por ejemplo, cada tienda venderá una gama diferente de productos, y cada producto se vende en muchas tiendas diferentes. - -A fin de mantener la información de contexto para "colocar un producto en un estante de una tienda determinada", será necesario crear una nueva entidad de datos **InventoryItem** que exista para asociar los datos de otras entidades. Tiene una relación clave ajena a las entidades **Store**, **Shelf** y **Product** y por lo tanto requiere atributos de relación llamados `refStore`, `refShelf` y `refProduct`. - -La asignación de un producto a un estante se hace simplemente creando una entidad que contenga la información de la relación y cualquier otra propiedad adicional (como `StockCount` y `ShelfCount`) - -#### 9️⃣ Solicitud: - -```console -curl -iX POST \ - 'http://localhost:1026/v2/entities' \ - -H 'Content-Type: application/json' \ - -d '{ - "id": "urn:ngsi-ld:InventoryItem:001", "type": "InventoryItem", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:001" - }, - "refShelf": { - "type": "Relationship", - "value": "urn:ngsi-ld:Shelf:unit001" - }, - "refProduct": { - "type": "Relationship", - "value": "urn:ngsi-ld:Product:001" - }, - "stockCount":{ - "type":"Integer", "value": 10000 - }, - "shelfCount":{ - "type":"Integer", "value": 50 - } -}' -``` - -## Leyendo desde una tabla puente - -Cuando se lee de una entidad de la tabla puente, el `type` de la entidad debe ser conocido. - -Después de crear al menos una entidad **InventoryItem** podemos consultar _¿Qué productos se venden en `urn:ngsi-ld:Store:001`?_ haciendo la siguiente petición - -#### 1️⃣0️⃣ Solicitud: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&options=values&attrs=refProduct&type=InventoryItem' -``` - -#### Respuesta: - -```json -[["urn:ngsi-ld:Product:prod001"]] -``` - -Del mismo modo, podemos consultar _¿Qué tiendas están vendiendo `urn:ngsi-ld:Product:001`?_ alterando la petición como se muestra: - -#### 1️⃣1️⃣ Solicitud: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refProduct==urn:ngsi-ld:Product:001&options=values&attrs=refStore&type=InventoryItem' -``` - -#### Respuesta: - -```json -[["urn:ngsi-ld:Store:001"]] -``` - -## Integridad de los datos - -Las relaciones de datos de contexto sólo deben establecerse y mantenerse entre entidades que existan - en otras palabras, la URN `urn:ngsi-ld::` debe vincularse a otra entidad existente dentro del contexto. Por lo tanto, debemos tener cuidado al borrar una entidad de que no queden referencias colgantes. Imagina que se borra `urn:ngsi-ld:Store:001` - ¿qué debería pasar con las entidades **Shelf** asociadas? - -Es posible hacer una solicitud para ver si existe alguna relación de entidad restante antes de la supresión, haciendo una solicitud como la siguiente - -#### 1️⃣2️⃣ Solicitud: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&options=count&attrs=type' -``` - -#### 1️⃣3️⃣ Solicitud: - -La respuesta enumera una serie de entidades de **Shelf** y **InventoryItem** - no hay entidades de **Product** ya que no hay una relación directa entre el producto y la tienda. - -```json -[ - { - "id": "urn:ngsi-ld:Shelf:unit001", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:Shelf:unit002", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:Shelf:unit003", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:InventoryItem:001", - "type": "InventoryItem" - } -] -``` - -Si esta solicitud devuelve un arreglo vacío, la entidad no tiene objetos asociados. - -# Próximos pasos - -¿Quieres aprender a añadir más complejidad a tu aplicación añadiendo funciones avanzadas? Puedes averiguarlo leyendo -los otros [tutoriales de esta serie](https://fiware-tutorials.rtfd.io) - ---- - -## Licencia - -[MIT](LICENSE) © 2018-2020 FIWARE Foundation e.V. diff --git a/README.ja.md b/README.ja.md deleted file mode 100644 index 7d7ca56..0000000 --- a/README.ja.md +++ /dev/null @@ -1,781 +0,0 @@ -[![FIWARE Banner](https://fiware.github.io/tutorials.Entity-Relationships/img/fiware.png)](https://www.fiware.org/developers) -[![NGSI v2](https://img.shields.io/badge/NGSI-v2-5dc0cf.svg)](https://fiware-ges.github.io/orion/api/v2/stable/) - -[![FIWARE Core Context Management](https://nexus.lab.fiware.org/repository/raw/public/badges/chapters/core.svg)](https://github.com/FIWARE/catalogue/blob/master/core/README.md) -[![License: MIT](https://img.shields.io/github/license/fiware/tutorials.Entity-Relationships.svg)](https://opensource.org/licenses/MIT) -[![Support badge](https://img.shields.io/badge/tag-fiware-orange.svg?logo=stackoverflow)](https://stackoverflow.com/questions/tagged/fiware) -
[![Documentation](https://img.shields.io/readthedocs/fiware-tutorials.svg)](https://fiware-tutorials.rtfd.io) - - - -このチュートリアルでは、FIWARE ユーザにバッチコマンドとエンティティのリレーショ -ンシップについて説明しています。チュートリアルでは、以前 -の[ストア・ファインダの例](https://github.com/FIWARE/tutorials.Getting-Started)で -作成されたデータを基にして、一連の関連するデータ・エンティティを作成して関連付け -て、単純な在庫管理システムを作成します。 - -このチュートリアルでは、[cUrl](https://ec.haxx.se/) コマンドを使用していますが -、[Postman documentation](https://fiware.github.io/tutorials.Entity-Relationships/) -も利用できます。 - -[![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/0671934f64958d3200b3) -[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/FIWARE/tutorials.Entity-Relationships/tree/NGSI-v2) - -# コンテンツ - -
-詳細 (クリックして拡大) - -- [エンティティとリレーションシップの理解](#understanding-entities-and-relationships) - - [在庫システム内のエンティティ](#entities-within-a-stock-management-system) -- [アーキテクチャ](#architecture) -- [前提条件](#prerequisites) - - [Docker と Docker Compose](#docker-and-docker-compose) - - [Cygwin for Windows](#cygwin-for-windows) -- [起動](#start-up) -- [データ・エンティティの作成と関連付け](#creating-and-associating-data-entities) - - [一度に複数のエンティティを作成](#creating-several-entities-at-once) - - [1 対多のリレーションシップの作成](#creating-a-one-to-many-relationship) - - [外部キーのリレーションシップの読み取り](#reading-a-foreign-key-relationship) - - [子エンティティから親エンティティへの読み取り](#reading-from-child-entity-to-parent-entity) - - [親エンティティから子エンティティへの読み取り](#reading-from-parent-entity-to-child-entity) - - [多対多のリレーションシップの作成](#creating-many-to-many-relationships) - - [ブリッジ・テーブルからの読み込み](#reading-from-a-bridge-table) - - [データの整合性](#data-integrity) -- [次のステップ](#next-steps) - -
- - - -# エンティティとリレーションシップの理解 - -FIWARE プラットフォーム内では、エンティティのコンテキストは、実世界に存在する物 -理的または概念的オブジェクトの状態を表します。 - - - -## 在庫システム内のエンティティ - -シンプルな在庫管理システムでは、4 つのタイプのエンティティのみが必要となります。 -エンティティ間のリレーションシップは、次のように定義されます : - -![](https://fiware.github.io/tutorials.Entity-Relationships/img/entities.png) - -- **Store** : ストアは実世界のレンガとモルタルの建物です。ストアには次のような - プロパティがあります : - - name : ストアの名前。例えば、"Checkpoint Markt" - - address : ストアの住所。例えば、"Friedrichstraße 44, 10969 Kreuzberg, - Berlin" - - location : ストアの物理的なローケーション。例えば、_52.5075 N, 13.3903 - E_ -- **Shelf** : 棚は販売したいオブジェクトを保持するための、現実世界のデバイスで - す。各棚には次のようなプロパティがあります : - - name : 棚の名前。例えば、"Wall Unit" - - location : 棚の物理的なローケーション。例えば、_52.5075 N, 13.3903 E_ - - maximum_capacity : 棚の最大容量 - - 棚(shelf)が存在するストア(store)への関連付け -- **Product** : 製品は販売するものとして定義されています。それは概念的なオブジ - クトです。製品には次のような特性があります : - - name : 製品の名前。例えば、"Melons" - - price : 製品の価格。例えば、13.99 ユーロ - - size : 製品のサイズ。例えば、小さい -- **Inventory Item** : インベントリ項目は製品、店舗、棚、および物理的な物を関 - 連付けるために使用される別の概念エンティティです。以下のようなプロパティを持 - ちます : - - product : 販売されている製品へのアソシエーション - - store : 製品が販売されている店舗への関連付け - - shelf : 製品が展示されている棚への関連 - - stock_count : 倉庫で利用可能な製品の在庫数 - - stelf_count : 棚で利用可能な製品の在庫数 - -ご覧のとおり、上記で定義されたエンティティのそれぞれは、変更される可能性のあるい -くつかのプロパティを含んでいます。製品の価格が変わる可能性があり、在庫が売却され -、在庫の在庫数が減る可能性があります。 - -> **注** このチュートリアルでは、次の表記スタイルを使用しています : -> -> - エンティティタイプは**太字**です -> - データ属性は `monospace text` に記述されています -> - 現実世界のアイテムはプレーン・テキストを使用します -> -> したがって、現実世界のストアは、**Store** エンティティによってコンテキスト・デ -> ータ内に表され、ストア内にある現実世界の棚は、`refStore` 属性を有する -> **Shelf** エンティティによってコンテキスト・データに表されます。 - - - -# アーキテクチャ - -このアプリケーションは -、[Orion Context Broker](https://catalogue.fiware.org/enablers/publishsubscribe-context-broker-orion-context-broker) -という 1 つの FIWARE コンポーネントしか使用しません。アプリケーションが -_"Powered by FIWARE"_ と認定するには、Orion Context Broker を使用するだけで十分 -です。 - -現在、Orion Context Broker はオープンソースの -[MongoDB](https://www.mongodb.com/) 技術を利用して、コンテキスト・データの永続性 -を維持しています。したがって、アーキテクチャは 2 つの要素で構成されます : - -- [NGSI-v2](https://fiware.github.io/specifications/OpenAPI/ngsiv2) を使用してリ - クエストを受信する - [Orion Context Broker](https://fiware-orion.readthedocs.io/en/latest/) -- バックエンドの [MongoDB](https://www.mongodb.com/) データベース - - Orion Context Broker が、データ・エンティティなどのコンテキスト・データ - 情報、サブスクリプション、登録などを保持するために使用します - -2 つの要素間のすべての対話は HTTP リクエストによって開始されるため、エンティティ -はコンテナ化され、公開されたポートから実行されます。 - -![](https://fiware.github.io/tutorials.Entity-Relationships/img/architecture.png) - -必要な設定情報は、関連する `docker-compose.yml` ファイルの services セクションに -あります: - -```yaml -orion: - image: quay.io/fiware/orion:latest - hostname: orion - container_name: fiware-orion - depends_on: - - mongo-db - networks: - - default - expose: - - "1026" - ports: - - "1026:1026" - command: -dbhost mongo-db -logLevel DEBUG -``` - -```yaml -mongo-db: - image: mongo:4.2 - hostname: mongo-db - container_name: db-mongo - expose: - - "27017" - ports: - - "27017:27017" - networks: - - default - -``` - -両方のコンテナが同じネットワークに常駐しています。Orion Context Broker はポート -`1026` でリッスンしており、MongoDB はデフォルト・ポート `27017` でリッスンしてい -ます。 どちらのコンテナも同じポートを外部に公開しています。これはチュートリアル -のアクセス専用です。これにより、cUrl または Postman は同じネットワークに参加する -ことなくアクセスできます。 コマンドラインの初期化は、一目瞭然でなければなりませ -ん。 - - - -# 前提条件 - - - -## Docker と Docker Compose - -物事を単純にするために、両方のコンポーネントは [Docker](https://www.docker.com) -を使用して実行されます。**Docker** は、さまざまコンポーネントをそれぞれの環境に -分離することを可能にするコンテナ・テクノロジです。 - -- Docker を Windows にインストールするには - 、[こちら](https://docs.docker.com/docker-for-windows/)の手順に従ってくださ - い -- Docker を Mac にインストールするには - 、[こちら](https://docs.docker.com/docker-for-mac/)の手順に従ってください -- Docker を Linux にインストールするには - 、[こちら](https://docs.docker.com/install/)の手順に従ってください - -**Docker Compose** は、マルチコンテナ Docker アプリケーションを定義して実行する -ためのツールです -。[YAML file](https://raw.githubusercontent.com/Fiware/tutorials.Entity-Relationships/NGSI-v2/docker-compose.yml) -ファイルは、アプリケーションのために必要なサービスを構成するために使用します。つ -まり、すべてのコンテナ・サービスは 1 つのコマンドで呼び出すことができます -。Docker Compose は、デフォルトで Docker for Windows と D ocker for Mac の一部と -してインストールされますが、Linux ユーザ -は[ここ](https://docs.docker.com/compose/install/)に記載されている手順に従う必要 -があります。 - -次のコマンドを使用して、現在の **Docker** バージョンと **Docker Compose** バージ -ョンを確認できます : - -```console -docker-compose -v -docker version -``` - -Docker バージョン 20.10 以降と Docker Compose 1.29 以上を使用していることを確認 -し、必要に応じてアップグレードしてください。 - - - -## Cygwin for Windows - -シンプルな Bash スクリプトを使用してサービスを開始します。Windows ユーザは -[cygwin](http://www.cygwin.com/) をダウンロードして、Windows の Linux ディストリ -ビューションに似たコマンドライン機能を提供する必要があります。 - - - -# 起動 - -リポジトリ内で Bash スクリプトが提供する -[services](https://github.com/FIWARE/tutorials.Entity-Relationships/blob/NGSI-v2/services) -を実行することにより、コマンドラインからすべてのサービスを初期化することができま -す。リポジトリを複製し、以下のコマンドを実行して必要なイメージを作成してください -: - -```console -git clone https://github.com/FIWARE/tutorials.Entity-Relationships.git -cd tutorials.Entity-Relationships -git checkout NGSI-v2 - -./services start -``` - -このコマンドは、起動時に以前 -の[ストア・ファインダのチュートリアル](https://github.com/FIWARE/tutorials.Getting-Started)の -シード・データもインポートします。 - -> **注** : クリーンアップをやり直したい場合は、次のコマンドを使用して再起動する -> ことができます : - -```console -./services stop -``` - -> - - - -# データ・エンティティの作成と関連付け - - - -## 一度に複数のエンティティを作成 - -前のチュートリアルでは、各ストアのエンティティを個別に作成しました。 - -同時に 5 つの棚ユニットを作成できます。このリクエストでは、簡易バッチ処理エンド -ポイントを使用して 5 つの棚エンティティを作成します。バッチ処理では、2 つの属性 -を持つペイロードで `/v2/op/update` エンドポイントを使用します -。`actionType=APPEND` は、既存のエンティティが存在する場合はそれを上書きすること -を意味しますが、`entities` 属性は更新するエンティティの配列を保持します。 - -**Store** エンティティから **Shelf** エンティティを区別するために、各棚が -`type=Shelf` に割り当てられています。'name' と 'location' のような実世界のプロパ -ティが各棚にプロパティとして追加されました。 - -#### 1️⃣ リクエスト : - -```console -curl -iX POST \ - 'http://localhost:1026/v2/op/update' \ - -H 'Content-Type: application/json' \ - -d '{ - "actionType":"APPEND", - "entities":[ - { - "id":"urn:ngsi-ld:Shelf:unit001", "type":"Shelf", - "location":{ - "type":"geo:json", "value":{ "type":"Point","coordinates":[13.3986112, 52.554699]} - }, - "name":{ - "type":"Text", "value":"Corner Unit" - }, - "maxCapacity":{ - "type":"Integer", "value":50 - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit002", "type":"Shelf", - "location":{ - "type":"geo:json","value":{"type":"Point","coordinates":[13.3987221, 52.5546640]} - }, - "name":{ - "type":"Text", "value":"Wall Unit 1" - }, - "maxCapacity":{ - "type":"Integer", "value":100 - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit003", "type":"Shelf", - "location":{ - "type":"geo:json", "value":{"type":"Point","coordinates":[13.3987221, 52.5546640]} - }, - "name":{ - "type":"Text", "value":"Wall Unit 2" - }, - "maxCapacity":{ - "type":"Integer", "value":100 - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit004", "type":"Shelf", - "location":{ - "type":"geo:json", "value":{"type":"Point","coordinates":[13.390311, 52.507522]} - }, - "name":{ - "type":"Text", "value":"Corner Unit" - }, - "maxCapacity":{ - "type":"Integer", "value":50 - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit005", "type":"Shelf", - "location":{ - "type":"geo:json","value":{"type":"Point","coordinates":[13.390309, 52.50751]} - }, - "name":{ - "type":"Text", "value":"Long Wall Unit" - }, - "maxCapacity":{ - "type":"Integer", "value":200 - } - } - ] -}' -``` - -同様に、`type=Product` を使用して一連の **Product** エンティティを作成できます。 - -#### 2️⃣ リクエスト : - -```console -curl -iX POST \ - 'http://localhost:1026/v2/op/update' \ - -H 'Content-Type: application/json' \ - -d '{ - "actionType":"APPEND", - "entities":[ - { - "id":"urn:ngsi-ld:Product:001", "type":"Product", - "name":{ - "type":"Text", "value":"Apples" - }, - "size":{ - "type":"Text", "value": "S" - }, - "price":{ - "type":"Integer", "value": 99 - } - }, - { - "id":"urn:ngsi-ld:Product:002", "type":"Product", - "name":{ - "type":"Text", "value":"Bananas" - }, - "size":{ - "type":"Text", "value": "M" - }, - "price":{ - "type":"Integer", "value": 1099 - } - }, - { - "id":"urn:ngsi-ld:Product:003", "type":"Product", - "name":{ - "type":"Text", "value":"Coconuts" - }, - "size":{ - "type":"Text", "value": "M" - }, - "price":{ - "type":"Integer", "value": 1499 - } - }, - { - "id":"urn:ngsi-ld:Product:004", "type":"Product", - "name":{ - "type":"Text", "value":"Melons" - }, - "size":{ - "type":"Text", "value": "XL" - }, - "price":{ - "type":"Integer", "value": 5000 - } - } - ] -}' -``` - -どちらの場合も、NGSI-LD -[ドラフト勧告](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.08.01_60/gs_cim009v010801p.pdf)に -従って各エンティティ `id` をエンコードしました。提案は、それぞれの `id` が 標準 -フォーマットに従った URN というものです : -`urn:ngsi-ld::`。これは、システム内のすべての `id` がユ -ニークであることを意味します。 - -棚情報は、`/v2/entities` エンドポイントで GET リクエストを行うことでリクエストで -きます。たとえば、`id=urn:ngsi-ld:Shelf:unit001` を使用すると、その **Shelf** エ -ンティティのコンテキスト・データが得られます : - -#### 3️⃣ リクエスト : - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/urn:ngsi-ld:Shelf:unit001/?type=Shelf&options=keyValues' -``` - -#### レスポンス : - -```json -{ - "id": "urn:ngsi-ld:Shelf:unit001", - "type": "Shelf", - "location": { - "type": "Point", - "coordinates": [13.3986112, 52.554699] - }, - "maxCapacity": 50, - "name": "Corner Unit" -} -``` - -このように、存在する 3 つの追加のプロパティ属性 `location`, `maxCapacity` と -`name` があります。 - - - -## 1 対多のリレーションシップの作成 - -データベースでは、外部キーは 1 対多のリレーションシップを指定するためによく使用 -されます。たとえば、すべての棚が 1 つのストアにあり、1 つのストアには多くの棚ユ -ニットがあります。この情報を記憶するためには、外部キーと同様のアソシエーション・ -リレーションシップを追加する必要があります。バッチ処理を再び使用して、既存の -**Shelf** エンティティを修正して、各ストアにリレーションシップを保持する -`refStore` 属性を追加することができます -。[リンクト・データ](https://smartdatamodels.org/) -に関する スマート・データ・モデリング・ガイドラインによると、エンティティ属性が他の -エンティティへのリンクとして使用される場合、プレフィックス `ref` と ターゲットの -リンクト・エンティティ・タイプの名前を付けて名前を付ける必要があります。 - -`refStore` 属性値は、**Store** エンティティ自体に関連付けられた URN に対応します -。 - -URN は標準フォーマットに従います : `urn:ngsi-ld::` - -#### 4️⃣ リクエスト : - -次のリクエストは、3 つの棚を `urn:ngsi-ld:Store:001` に、2 つの棚を -`urn:ngsi-ld:Store:002` に関連付けます。 - -```console -curl -iX POST \ - 'http://localhost:1026/v2/op/update' \ - -H 'Content-Type: application/json' \ - -d '{ - "actionType":"APPEND", - "entities":[ - { - "id":"urn:ngsi-ld:Shelf:unit001", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:001" - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit002", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:001" - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit003", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:001" - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit004", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:002" - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit005", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:002" - } - } - ] -}' -``` - -ここで棚情報が再度リクエストされると、レスポンスが変更され、前の手順で追加された -新しい `refStore` 属性が含まれます。 - -#### 5️⃣ リクエスト : - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/urn:ngsi-ld:Shelf:unit001/?type=Shelf&options=keyValues' -``` - -#### レスポンス : - -`refStore` 属性を含む更新されたレスポンスを以下に示します : - -```json -{ - "id": "urn:ngsi-ld:Shelf:unit001", - "type": "Shelf", - "location": { - "type": "Point", - "coordinates": [13.3986112, 52.554699] - }, - "maxCapacity": 50, - "name": "Corner Unit", - "refStore": "urn:ngsi-ld:Store:001" -} -``` - - - -## 外部キーのリレーションシップの読み取り - - - -### 子エンティティから親エンティティへの読み取り - -また、`options=values` 設定を使用して、既知の棚エンティティから `refStore` 属性 -のリレーションシップ情報を取得するようリクエストすることもできます : - -#### 6️⃣ リクエスト : - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/urn:ngsi-ld:Shelf:unit001/?type=Shelf&options=values&attrs=refStore' -``` - -#### レスポンス : - -```json -["urn:ngsi-ld:Store:001"] -``` - -これは、"私は、`id=urn:ngsi-ld:Store:001` で **Store**エンティティと関連していま -す"と、解釈することができます。 - - - -### 親エンティティから子エンティティへの読み取り - -親から子への読み込みは、`options=count` 設定を使用して行うことができます : - -#### 7️⃣ リクエスト : - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&options=count&attrs=type&type=Shelf' -``` - -このリクエストは、URN `urn:ngsi-ld:Store:001` に関連付けられているすべての -**Shelf** エンティティの `id` をリクエストしています。レスポンスは、次に示されて -いるように JSON 配列です。 - -#### レスポンス : - -```json -[ - { - "id": "urn:ngsi-ld:Shelf:unit001", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:Shelf:unit002", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:Shelf:unit003", - "type": "Shelf" - } -] -``` - -普通の英語では、これは"`urn:ngsi-ld:Store:001` の中に 3 つの棚があります"と解釈 -することができます。リクエストを変更して、`options=values` と `attrs` パラメータ -を使用して、関連する関連エンティティの特定のプロパティを返すことができます。例え -ば、次のようなリクエストです : - -#### 8️⃣ リクエスト : - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&type=Shelf&options=values&attrs=name' -``` - -_"`urn:ngsi-ld:Store:001` にあるすべての棚の名前を教えてください。"_ というリク -エストとして解釈することができます。 - -#### レスポンス : - -```json -[["Corner Unit"], ["Wall Unit 1"], ["Wall Unit 2"]] -``` - - - -## 多対多のリレーションシップの作成 - -ブリッジ・テーブルは、多対多のリレーションシップを関連付けるためによく使用されま -す。たとえば、各ストアではさまざまな種類の商品が販売され、各商品はさまざまなスト -アで販売されます。 - -ブリッジ・テーブルは、多対多のリレーションシップを関連付けるためによく使用されま -す。たとえば、各ストアではさまざまな種類の商品が販売され、各商品はさまざまなスト -アで販売されます。 - -コンテキスト情報を"所与のストアの棚に製品を置く"ように保持するためには、他のエン -ティティからのデータを関連付けるために存在する新しいデータ・エンティティ -**InventoryItem** を作成する必要があります。それは、**Store**, **Shelf** と -**Product** エンティティとは外部キー関係を持つので、`refStore`、`refShelf`、およ -び `refProduct` というリレーションシップ属性が必要です。 - -製品を棚に割り当てることは、単にリレーションシップ情報と、`stockCount` と -`shelfCount` のようなその他の追加プロパティを保持するエンティティを作成すること -によって行われます。 - -#### 9️⃣ リクエスト : - -```console -curl -iX POST \ - 'http://localhost:1026/v2/entities' \ - -H 'Content-Type: application/json' \ - -d '{ - "id": "urn:ngsi-ld:InventoryItem:001", "type": "InventoryItem", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:001" - }, - "refShelf": { - "type": "Relationship", - "value": "urn:ngsi-ld:Shelf:unit001" - }, - "refProduct": { - "type": "Relationship", - "value": "urn:ngsi-ld:Product:001" - }, - "stockCount":{ - "type":"Integer", "value": 10000 - }, - "shelfCount":{ - "type":"Integer", "value": 50 - } -}' -``` - - - -## ブリッジ・テーブルからの読み込み - -ブリッジ・テーブル・エンティティから読み込む場合、エンティティの `type` を知る必 -要があります。 - -少なくとも 1 つの **InventoryItem** エンティティを作成した後、次のリクエストを行 -うことで、_"`urn:ngsi-ld:Store:001` の中にどの製品が販売されているか?"_ をクエ -リすることができます。 - -#### 1️⃣0️⃣ リクエスト : - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&options=values&attrs=refProduct&type=InventoryItem' -``` - -#### レスポンス : - -```json -[["urn:ngsi-ld:Product:prod001"]] -``` - -同様に、次のようにリクエストを変更することで、どのストアで -`urn:ngsi-ld:Product:001` が売れているのかを知ることができます : - -#### 1️⃣1️⃣ リクエスト : - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refProduct==urn:ngsi-ld:Product:001&options=values&attrs=refStore&type=InventoryItem' -``` - -#### レスポンス : - -```json -[["urn:ngsi-ld:Store:001"]] -``` - - - -## データの整合性 - -コンテキスト・データのリレーションシップは、存在するエンティティ間でのみ設定およ -び維持する必要があります。つまり、URN `urn:ngsi-ld::` は -コンテキスト内の別の既存エンティティにリンクする必要があります。したがって、ダン -グリング・リファレンスが残っていないエンティティを削除するときは、注意が必要です -。`urn:ngsi-ld:Store:001` が削除されたと想像してください。関連する **Shelf** の -エンティティに何が起こるべきですか? - -以下のようにリクエストすることにより、削除前に残っているエンティティのリレーショ -ンシップが存在するかどうかを確認するリクエストを出すことができます : - -#### 1️⃣2️⃣ リクエスト : - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&options=count&attrs=type' -``` - -#### 1️⃣3️⃣ リクエスト : - -このレスポンスには一連の **Shelf** と **InventoryItem** エンティティがリストされ -ています。製品とストアの間に直接のリレーションシップがないため、**Product** エン -ティティはありません。 - -```json -[ - { - "id": "urn:ngsi-ld:Shelf:unit001", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:Shelf:unit002", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:Shelf:unit003", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:InventoryItem:001", - "type": "InventoryItem" - } -] -``` - -このリクエストによって空の配列が返された場合、エンティティには関連がありません。 - - - -# 次のステップ - -高度な機能を追加することで、アプリケーションに複雑さを加える方法を知りたいですか -?このシリーズ -の[他のチュートリアル](https://www.letsfiware.jp/fiware-tutorials)を読むことで見 -つけることができます : - ---- - -## License - -[MIT](LICENSE) © 2018-2024 FIWARE Foundation e.V. diff --git a/README.md b/README.md index 444975e..6c316e5 100644 --- a/README.md +++ b/README.md @@ -1,688 +1,50 @@ [![FIWARE Banner](https://fiware.github.io/tutorials.Entity-Relationships/img/fiware.png)](https://www.fiware.org/developers) -[![NGSI v2](https://img.shields.io/badge/NGSI-v2-5dc0cf.svg)](https://fiware-ges.github.io/orion/api/v2/stable/) [![FIWARE Core Context Management](https://nexus.lab.fiware.org/repository/raw/public/badges/chapters/core.svg)](https://github.com/FIWARE/catalogue/blob/master/core/README.md) [![License: MIT](https://img.shields.io/github/license/fiware/tutorials.Entity-Relationships.svg)](https://opensource.org/licenses/MIT) [![Support badge](https://img.shields.io/badge/tag-fiware-orange.svg?logo=stackoverflow)](https://stackoverflow.com/questions/tagged/fiware) -
[![Documentation](https://img.shields.io/readthedocs/fiware-tutorials.svg)](https://fiware-tutorials.rtfd.io) -This tutorial teaches FIWARE users about batch commands and entity relationships. The tutorial builds on the data +These tutorials teach FIWARE users about batch commands and entity relationships. The tutorial builds on the data created in the previous [store finder example](https://github.com/FIWARE/tutorials.Getting-Started) and creates and associates a series of related data entities to create a simple stock management system. The tutorial uses [cUrl](https://ec.haxx.se/) commands throughout, but is also available as -[Postman documentation](https://fiware.github.io/tutorials.Entity-Relationships/). +[Postman documentation](https://www.postman.com/downloads/). -[![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/0671934f64958d3200b3) -[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/FIWARE/tutorials.Entity-Relationships/tree/NGSI-v2) +# Start-Up -🇯🇵 このチュートリアルは[日本語](https://github.com/FIWARE/tutorials.Entity-Relationships/blob/master/README.ja.md)でもご -覧いただけます。
🇪🇸 Este tutorial también está disponible en -[español](https://github.com/FIWARE/tutorials.Entity-Relationships/blob/master/README.es.md) +## NGSI-v2 Smart Supermarket -## Contents - -
-Details - -- [Understanding Entities and Relationships](#understanding-entities-and-relationships) - - [Entities within a stock management system](#entities-within-a-stock-management-system) -- [Architecture](#architecture) -- [Prerequisites](#prerequisites) - - [Docker and Docker Compose](#docker-and-docker-compose) - - [Cygwin for Windows](#cygwin-for-windows) -- [Start Up](#start-up) -- [Creating and Associating Data Entities](#creating-and-associating-data-entities) - - [Creating Several Entities at Once](#creating-several-entities-at-once) - - [Creating a one-to-many Relationship](#creating-a-one-to-many-relationship) - - [Reading a Foreign Key Relationship](#reading-a-foreign-key-relationship) - - [Reading from Child Entity to Parent Entity](#reading-from-child-entity-to-parent-entity) - - [Reading from Parent Entity to Child Entity](#reading-from-parent-entity-to-child-entity) - - [Creating many-to-many Relationships](#creating-many-to-many-relationships) - - [Reading from a bridge table](#reading-from-a-bridge-table) - - [Data Integrity](#data-integrity) -- [Next Steps](#next-steps) - -
- -# Understanding Entities and Relationships - -> “It is not the amount of knowledge that makes a brain. It is not even the distribution of knowledge. It is the interconnectedness.” -> -> ― James Gleick, The Information: A History, a Theory, a Flood - -Within the FIWARE platform, the context of an entity represents the state of a physical or conceptual object which -exists in the real world. The connection from one entity to another is expressed using a **Relationship**, enabling users -to make inferences across the whole knowledge graph of the system. - -## Entities within a stock management system - -For a simple stock management system, we will only need four types of entity. The relationship between our entities is -defined as shown: - -![](https://fiware.github.io/tutorials.Entity-Relationships/img/entities.png) - -- A store is a real world bricks and mortar building. **Store** entities would have properties such as: - - A name of the store e.g. "Checkpoint Markt" - - An address "Friedrichstraße 44, 10969 Kreuzberg, Berlin" - - A phyiscal location e.g. _52.5075 N, 13.3903 E_ -- A shelf is a real world device to hold objects which we wish to sell. Each **Shelf** entity would have properties - such as: - - A name of the shelf e.g. "Wall Unit" - - A phyiscal location e.g. _52.5075 N, 13.3903 E_ - - A maximum capacity - - An association to the store in which the shelf is present -- A product is defined as something that we sell - it is conceptural object. **Product** entities would have - properties such as: - - A name of the product e.g. "Melons" - - A price e.g. 13.99 Euros - - A size e.g. Small -- An inventory item is another conceptural entity, used to assocate products, stores, shelves and physical objects. - **Inventory Item** entities would have properties such as: - - An association to the product being sold - - An association to the store in which the product is being sold - - An association to the shelf where the product is being displayed - - A stock count of the quantity of the product available in the warehouse - - A stock count of the quantity of the product available on the shelf - -As you can see, each of the entities defined above contain some properties which are liable to change. A product could -change its price, stock could be sold and the shelf count of stock could be reduced and so on. - -> [!NOTE] -> This tutorial uses the following typographic styling : -> -> - Entity types have been made **bold text** -> - Data attributes are written in `monospace text` -> - Items in the real world use plain text -> -> Therefore a store in the real world is represented in the context data by a **Store** entity, and a real world shelf -> found in a store is represented in the context data by a **Shelf** entity which has a `refStore` attribute. - -# Architecture - -This application will only make use of one FIWARE component - the -[Orion Context Broker](https://fiware-orion.readthedocs.io/en/latest/). Usage of the Orion Context Broker is sufficient -for an application to qualify as _“Powered by FIWARE”_. - -Currently, the Orion Context Broker relies on open source [MongoDB](https://www.mongodb.com/) technology to keep -persistence of the context data it holds. Therefore, the architecture will consist of two elements: - -- The [Orion Context Broker](https://fiware-orion.readthedocs.io/en/latest/) which will receive requests using - [NGSI-v2](https://fiware.github.io/specifications/OpenAPI/ngsiv2) -- The underlying [MongoDB](https://www.mongodb.com/) database : - - Used by the Orion Context Broker to hold context data information such as data entities, subscriptions and - registrations - -Since all interactions between the two elements are initiated by HTTP requests, the entities can be containerized and -run from exposed ports. - -![](https://fiware.github.io/tutorials.Entity-Relationships/img/architecture.png) - -The necessary configuration information can be seen in the services section of the associated `docker-compose.yml` file: - -```yaml -orion: - image: quay.io/fiware/orion:latest - hostname: orion - container_name: fiware-orion - depends_on: - - mongo-db - networks: - - default - expose: - - '1026' - ports: - - '1026:1026' - command: -dbhost mongo-db -logLevel DEBUG -``` - -```yaml -mongo-db: - image: mongo:4.2 - hostname: mongo-db - container_name: db-mongo - expose: - - '27017' - ports: - - '27017:27017' - networks: - - default -``` - -Both containers are residing on the same network - the Orion Context Broker is listening on Port `1026` and MongoDB is -listening on the default port `27017`. Both containers are also exposing the same ports externally - this is purely for -the tutorial access - so that cUrl or Postman can access them without being part of the same network. The command-line -initialization should be self explanatory. - -# Prerequisites - -## Docker and Docker Compose - -To keep things simple both components will be run using [Docker](https://www.docker.com). **Docker** is a container -technology which allows to different components isolated into their respective environments. - -- To install Docker on Windows follow the instructions [here](https://docs.docker.com/docker-for-windows/) -- To install Docker on Mac follow the instructions [here](https://docs.docker.com/docker-for-mac/) -- To install Docker on Linux follow the instructions [here](https://docs.docker.com/install/) - -**Docker Compose** is a tool for defining and running multi-container Docker applications. A -[YAML file](https://raw.githubusercontent.com/Fiware/tutorials.Entity-Relationships/master/docker-compose.yml) is used -configure the required services for the application. This means all container services can be brought up in a single -command. Docker Compose is installed by default as part of Docker for Windows and Docker for Mac, however Linux users -will need to follow the instructions found [here](https://docs.docker.com/compose/install/) - -You can check your current **Docker** and **Docker Compose** versions using the following commands: - -```console -docker-compose -v -docker version -``` - -Please ensure that you are using Docker version 20.10 or higher and Docker Compose 1.29 or higher and upgrade if -necessary. - -## Cygwin for Windows - -We will start up our services using a simple Bash script. Windows users should download [cygwin](http://www.cygwin.com/) -to provide a command-line functionality similar to a Linux distribution on Windows. - -# Start Up - -All services can be initialised from the command-line by running the -[services](https://github.com/FIWARE/tutorials.Entity-Relationships/blob/NGSI-v2/services) Bash script provided within -the repository. Please clone the repository and create the necessary images by running the commands as shown: +**NGSI-v2** offers JSON based interoperability used in individual Smart Systems. To run this tutorial with **NGSI-v2**, use the `NGSI-v2` branch. ```console git clone https://github.com/FIWARE/tutorials.Entity-Relationships.git cd tutorials.Entity-Relationships git checkout NGSI-v2 +./services create ./services start ``` -This command will also import seed data from the previous -[Store Finder tutorial](https://github.com/FIWARE/tutorials.Getting-Started) on startup. - -> [!NOTE] -> If you want to clean up and start over again you can do so with the following command: -> -> ```console -> ./services stop -> ``` - -# Creating and Associating Data Entities - -## Creating Several Entities at Once - -In the previous tutorial, we created each **Store** entity individually, - -Lets create five shelf units at the same time. This request uses the convenience batch processing endpoint to create -five shelf entities. Batch processing uses the `/v2/op/update` endpoint with a payload with two attributes - -`actionType=APPEND` means we will overwrite existing entities if they exist whereas the `entities` attribute holds an -array of entities we wish to update. - -To differenciate **Shelf** Entities from **Store** Entities, each shelf has been assigned `type=Shelf`. Real-world -properties such as `name` and `location` have been added as properties to each shelf. - -#### 1️⃣ Request: - -```console -curl -iX POST \ - 'http://localhost:1026/v2/op/update' \ - -H 'Content-Type: application/json' \ - -d '{ - "actionType":"APPEND", - "entities":[ - { - "id":"urn:ngsi-ld:Shelf:unit001", "type":"Shelf", - "location":{ - "type":"geo:json", "value":{ "type":"Point","coordinates":[13.3986112, 52.554699]} - }, - "name":{ - "type":"Text", "value":"Corner Unit" - }, - "maxCapacity":{ - "type":"Integer", "value":50 - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit002", "type":"Shelf", - "location":{ - "type":"geo:json","value":{"type":"Point","coordinates":[13.3987221, 52.5546640]} - }, - "name":{ - "type":"Text", "value":"Wall Unit 1" - }, - "maxCapacity":{ - "type":"Integer", "value":100 - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit003", "type":"Shelf", - "location":{ - "type":"geo:json", "value":{"type":"Point","coordinates":[13.3987221, 52.5546640]} - }, - "name":{ - "type":"Text", "value":"Wall Unit 2" - }, - "maxCapacity":{ - "type":"Integer", "value":100 - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit004", "type":"Shelf", - "location":{ - "type":"geo:json", "value":{"type":"Point","coordinates":[13.390311, 52.507522]} - }, - "name":{ - "type":"Text", "value":"Corner Unit" - }, - "maxCapacity":{ - "type":"Integer", "value":50 - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit005", "type":"Shelf", - "location":{ - "type":"geo:json","value":{"type":"Point","coordinates":[13.390309, 52.50751]} - }, - "name":{ - "type":"Text", "value":"Long Wall Unit" - }, - "maxCapacity":{ - "type":"Integer", "value":200 - } - } - ] -}' -``` - -Similarly, we can create a series of **Product** entities by using the `type=Product`. - -#### 2️⃣ Request: - -```console -curl -iX POST \ - 'http://localhost:1026/v2/op/update' \ - -H 'Content-Type: application/json' \ - -d '{ - "actionType":"APPEND", - "entities":[ - { - "id":"urn:ngsi-ld:Product:001", "type":"Product", - "name":{ - "type":"Text", "value":"Apples" - }, - "size":{ - "type":"Text", "value": "S" - }, - "price":{ - "type":"Integer", "value": 99 - } - }, - { - "id":"urn:ngsi-ld:Product:002", "type":"Product", - "name":{ - "type":"Text", "value":"Bananas" - }, - "size":{ - "type":"Text", "value": "M" - }, - "price":{ - "type":"Integer", "value": 1099 - } - }, - { - "id":"urn:ngsi-ld:Product:003", "type":"Product", - "name":{ - "type":"Text", "value":"Coconuts" - }, - "size":{ - "type":"Text", "value": "M" - }, - "price":{ - "type":"Integer", "value": 1499 - } - }, - { - "id":"urn:ngsi-ld:Product:004", "type":"Product", - "name":{ - "type":"Text", "value":"Melons" - }, - "size":{ - "type":"Text", "value": "XL" - }, - "price":{ - "type":"Integer", "value": 5000 - } - } - ] -}' -``` - -In both cases we have encoded each entity `id` according to the NGSI-LD -[specification](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.08.01_60/gs_cim009v010801p.pdf) - the proposal -is that each `id` is a URN follows a standard format: `urn:ngsi-ld::`. This will mean that every -`id` in the system will be unique. - -Shelf information can be requested by making a GET request on the `/v2/entities` endpoint. For example to return the -context data of the **Shelf** entity with the `id=urn:ngsi-ld:Shelf:unit001`. - -#### 3️⃣ Request: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/urn:ngsi-ld:Shelf:unit001/?type=Shelf&options=keyValues' -``` - -#### Response: - -```json -{ - "id": "urn:ngsi-ld:Shelf:unit001", - "type": "Shelf", - "location": { - "type": "Point", - "coordinates": [13.3986112, 52.554699] - }, - "maxCapacity": 50, - "name": "Corner Unit" -} -``` - -As you can see there are currently three additional property attributes present `location`, `maxCapacity` and `name` - -## Creating a one-to-many Relationship - -In databases, foreign keys are often used to designate a one-to-many relationship - for example every shelf is found in -a single store and a single store can hold many shelving units. In order to remember this information we need to add an -association relationship similar to a foreign key. Batch processing can again be used to amend the existing the -**Shelf** entities to add a `refStore` attribute holding the relationship to each store. According to the Smart Data -Modelling Guidelines on [linked data](https://smartdatamodels.org/), when an entity attribute is used as a link to other -entities it should be named with the prefix `ref` plus the name of the target (linked) entity type. - -The value of the `refStore` attribute corresponds to a URN associated to a **Store** entity itself. - -The URN follows a standard format: `urn:ngsi-ld::` - -#### 4️⃣ Request: - -The following request associates three shelves to `urn:ngsi-ld:Store:001` and two shelves to `urn:ngsi-ld:Store:002` - -```console -curl -iX POST \ - 'http://localhost:1026/v2/op/update' \ - -H 'Content-Type: application/json' \ - -d '{ - "actionType":"APPEND", - "entities":[ - { - "id":"urn:ngsi-ld:Shelf:unit001", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:001" - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit002", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:001" - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit003", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:001" - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit004", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:002" - } - }, - { - "id":"urn:ngsi-ld:Shelf:unit005", "type":"Shelf", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:002" - } - } - ] -}' -``` - -Now when the shelf information is requested again, the response has changed and includes a new property `refStore`, -which has been added in the previous step. +| [![NGSI v2](https://img.shields.io/badge/NGSI-v2-5dc0cf.svg)](https://fiware-ges.github.io/orion/api/v2/stable/) | :books: [Documentation](https://github.com/FIWARE/tutorials.Entity-Relationships/tree/NGSI-LD) | [Postman Collection](https://fiware.github.io/tutorials.Entity-Relationships/) | +| --- | --- | --- | -#### 5️⃣ Request: +## NGSI-LD Smart Farm -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/urn:ngsi-ld:Shelf:unit001/?type=Shelf&options=keyValues' -``` - -#### Response: - -The updated response including the `refStore` attribute is shown below: - -```json -{ - "id": "urn:ngsi-ld:Shelf:unit001", - "type": "Shelf", - "location": { - "type": "Point", - "coordinates": [13.3986112, 52.554699] - }, - "maxCapacity": 50, - "name": "Corner Unit", - "refStore": "urn:ngsi-ld:Store:001" -} -``` - -## Reading a Foreign Key Relationship - -### Reading from Child Entity to Parent Entity - -We can also make a request to retrieve the `refStore` attribute relationship information from a known **Shelf** entity -by using the `options=values` setting - -#### 6️⃣ Request: +**NGSI-LD** offers JSON-LD based interoperability used for Federations and Data Spaces. To run this tutorial with **NGSI-LD**, use the `NGSI-LD` branch. ```console -curl -X GET \ - 'http://localhost:1026/v2/entities/urn:ngsi-ld:Shelf:unit001/?type=Shelf&options=values&attrs=refStore' -``` - -#### Response: - -```json -["urn:ngsi-ld:Store:001"] -``` - -This can be interpreted as "I am related to the **Store** entity with the `id=urn:ngsi-ld:Store:001`" - -### Reading from Parent Entity to Child Entity - -Reading from a parent to a child can be done using the `options=count` setting - -#### 7️⃣ Request: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&options=count&attrs=type&type=Shelf' -``` - -This request is asking for the `id` of all **Shelf** entities associated to the URN `urn:ngsi-ld:Store:001`, the -response is a JSON array as shown. - -#### Response: - -```json -[ - { - "id": "urn:ngsi-ld:Shelf:unit001", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:Shelf:unit002", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:Shelf:unit003", - "type": "Shelf" - } -] -``` - -In plain English, this can be interpreted as "There are three shelves in `urn:ngsi-ld:Store:001`". The request can be -altered use the `options=values` and `attrs` parameters to return specific properties of the relevant associated -entities. For example the request: - -#### 8️⃣ Request: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&type=Shelf&options=values&attrs=name' -``` - -Can be interpreted as request for _Give me the names of all shelves in `urn:ngsi-ld:Store:001`_. - -#### Response: - -```json -[["Corner Unit"], ["Wall Unit 1"], ["Wall Unit 2"]] -``` - -## Creating many-to-many Relationships - -Bridge Tables are often used to relate many-to-many relationships. For example, every store will sell a different range -of products, and each product is sold in many different stores. - -In order to hold the context information to "place a product onto a shelf in a given store" we will need to create a new -data entity **InventoryItem** which exists to associate data from other entities. It has a foreign key relationship to -the **Store**, **Shelf** and **Product** entities and therefore requires relationship attributes called `refStore`, -`refShelf` and `refProduct`. - -Assigning a product to a shelf is simply done by creating an entity holding the relationship information and any other -additional properties (such as `stockCount` and `shelfCount`) - -#### 9️⃣ Request: - -```console -curl -iX POST \ - 'http://localhost:1026/v2/entities' \ - -H 'Content-Type: application/json' \ - -d '{ - "id": "urn:ngsi-ld:InventoryItem:001", "type": "InventoryItem", - "refStore": { - "type": "Relationship", - "value": "urn:ngsi-ld:Store:001" - }, - "refShelf": { - "type": "Relationship", - "value": "urn:ngsi-ld:Shelf:unit001" - }, - "refProduct": { - "type": "Relationship", - "value": "urn:ngsi-ld:Product:001" - }, - "stockCount":{ - "type":"Integer", "value": 10000 - }, - "shelfCount":{ - "type":"Integer", "value": 50 - } -}' -``` - -## Reading from a bridge table - -When reading from a bridge table entity, the `type` of the entity must be known. - -After creating at least one **InventoryItem** entity we can query _Which products are sold in `urn:ngsi-ld:Store:001`?_ -by making the following request - -#### 1️⃣0️⃣ Request: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&options=values&attrs=refProduct&type=InventoryItem' -``` - -#### Response: - -```json -[["urn:ngsi-ld:Product:prod001"]] -``` - -Similarly we can request _Which stores are selling `urn:ngsi-ld:Product:001`?_ by altering the request as shown: - -#### 1️⃣1️⃣ Request: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refProduct==urn:ngsi-ld:Product:001&options=values&attrs=refStore&type=InventoryItem' -``` - -#### Response: - -```json -[["urn:ngsi-ld:Store:001"]] -``` - -## Data Integrity - -Context data relationships should only be set up and maintained between entities that exist - in other words the URN -`urn:ngsi-ld::` should link to another existing entity within the context. Therefore we must -take care when deleting an entity that no dangling references remain. Imagine `urn:ngsi-ld:Store:001` is deleted - what -should happen to the associated the **Shelf** entities? - -It is possible to make a request to see if any remaining entity relationship exists prior to deletion by making a -request as follows - -#### 1️⃣2️⃣ Request: - -```console -curl -X GET \ - 'http://localhost:1026/v2/entities/?q=refStore==urn:ngsi-ld:Store:001&options=count&attrs=type' -``` - -#### 1️⃣3️⃣ Request: - -The response lists a series of **Shelf** and **InventoryItem** entities - there are no **Product** entities since there -is no direct relationship between product and store. +git clone https://github.com/FIWARE/tutorials.Entity-Relationships.git +cd tutorials.Entity-Relationships +git checkout NGSI-LD -```json -[ - { - "id": "urn:ngsi-ld:Shelf:unit001", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:Shelf:unit002", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:Shelf:unit003", - "type": "Shelf" - }, - { - "id": "urn:ngsi-ld:InventoryItem:001", - "type": "InventoryItem" - } -] +./services create +./services start ``` -If this request returns an empty array, the entity has no associates. - -# Next Steps +| [![NGSI LD](https://img.shields.io/badge/NGSI-LD-d6604d.svg)](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.08.01_60/gs_cim009v010801p.pdf) | :books: [Documentation](https://github.com/FIWARE/tutorials.Entity-Relationships/tree/NGSI-LD) | [Postman Collection](https://fiware.github.io/tutorials.Entity-Relationships/ngsi-ld.html) | +| --- | --- | --- | -Want to learn how to add more complexity to your application by adding advanced features? You can find out by reading -the other [tutorials in this series](https://fiware-tutorials.rtfd.io) --- diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index bced772..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,71 +0,0 @@ -# WARNING: Do not deploy this tutorial configuration directly to a production environment -# -# The tutorial docker-compose files have not been written for production deployment and will not -# scale. A proper architecture has been sacrificed to keep the narrative focused on the learning -# goals, they are just used to deploy everything onto a single Docker machine. All FIWARE components -# are running at full debug and extra ports have been exposed to allow for direct calls to services. -# They also contain various obvious security flaws - passwords in plain text, no load balancing, -# no use of HTTPS and so on. -# -# This is all to avoid the need of multiple machines, generating certificates, encrypting secrets -# and so on, purely so that a single docker-compose file can be read as an example to build on, -# not use directly. -# -# When deploying to a production environment, please refer to the Helm Repository -# for FIWARE Components in order to scale up to a proper architecture: -# -# see: https://github.com/FIWARE/helm-charts/ -# -version: "3.8" -services: - # Orion is an NGSI-v2 context broker - orion-v2: - labels: - org.fiware: 'tutorial' - image: quay.io/fiware/orion:${ORION_VERSION} - hostname: orion - container_name: fiware-orion - depends_on: - - mongo-db - networks: - - default - ports: - - "${ORION_PORT}:${ORION_PORT}" # localhost:1026 - command: -dbhost mongo-db -logLevel DEBUG -noCache - healthcheck: - test: curl --fail -s http://orion:${ORION_PORT}/version || exit 1 - interval: 5s - - # Databases - mongo-db: - labels: - org.fiware: 'tutorial' - image: mongo:${MONGO_DB_VERSION} - hostname: mongo-db - container_name: db-mongo - expose: - - "${MONGO_DB_PORT}" - ports: - - "${MONGO_DB_PORT}:${MONGO_DB_PORT}" # localhost:27017 # localhost:27017 - networks: - - default - volumes: - - mongo-db:/data - healthcheck: - test: ["CMD","mongosh", "--eval", "db.adminCommand('ping')"] - interval: 5s - timeout: 5s - retries: 3 - start_period: 5s - - -networks: - default: - labels: - org.fiware: 'tutorial' - ipam: - config: - - subnet: 172.18.1.0/24 - -volumes: - mongo-db: ~ diff --git a/import-data b/import-data deleted file mode 100755 index d1abc62..0000000 --- a/import-data +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash -# -# curl commands to reload the data from the previous tutorial -# -# - -set -e - -printf "⏳ Loading context data " - - -curl -s -o /dev/null -X POST \ - 'http://orion:1026/v2/op/update' \ - -H 'Content-Type: application/json' \ - -g -d '{ - "actionType": "append", - "entities": [ - { - "type": "Store", - "id": "urn:ngsi-ld:Store:001", - "address": { - "type": "PostalAddress", - "value": { - "streetAddress": "Bornholmer Straße 65", - "addressRegion": "Berlin", - "addressLocality": "Prenzlauer Berg", - "postalCode": "10439" - } - }, - "location": { - "type": "geo:json", - "value": { - "type": "Point", - "coordinates": [13.3986, 52.5547] - } - }, - "name": { - "type": "Text", - "value": "Bösebrücke Einkauf" - } - }, - { - "type": "Store", - "id": "urn:ngsi-ld:Store:002", - "address": { - "type": "PostalAddress", - "value": { - "streetAddress": "Friedrichstraße 44", - "addressRegion": "Berlin", - "addressLocality": "Kreuzberg", - "postalCode": "10969" - } - }, - "location": { - "type": "geo:json", - "value": { - "type": "Point", - "coordinates": [13.3903, 52.5075] - } - }, - "name": { - "type": "Text", - "value": "Checkpoint Markt" - } - } - ] -}' - -echo -e " \033[1;32mdone\033[0m" \ No newline at end of file diff --git a/services b/services index 041a10b..c744bc4 100755 --- a/services +++ b/services @@ -2,123 +2,8 @@ # # Command Line Interface to start all services associated with the Tutorial # -# For this tutorial the commands are merely a convenience script to run docker or docker-compose -# -# Each services script can be run using either docker-compose (the external tool with the hyphen -) -# or docker compose (the newer version directly bundled with Docker with a space ) -# -# if you start up with the following command: -# -# ./services start legacy -# -# This will force the script to use docker-compose which may be more reliable in -# some cases (or if an older version of Docker is being used) set -e -dockerCmd="docker compose" -if (( $# == 2 )); then - dockerCmd="docker-compose" -fi - -if (( $# < 1 )); then echo "Illegal number of parameters" - echo "usage: services [create|start|stop]" - exit 1 -fi - -loadData () { - docker run --rm -v $(pwd)/import-data:/import-data \ - --network fiware_default \ - --entrypoint /bin/ash quay.io/curl/curl /import-data - echo "" -} - -displayServices () { - echo "" - docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" --filter name=fiware-* - (gp ports list 2> /dev/null) || true - echo "" -} - -stoppingContainers () { - CONTAINERS=$(docker ps --filter "label=org.fiware=tutorial" -aq) - if [[ -n $CONTAINERS ]]; then - echo "Stopping containers" - docker rm -f $CONTAINERS || true - fi - VOLUMES=$(docker volume ls -qf dangling=true) - if [[ -n $VOLUMES ]]; then - echo "Removing old volumes" - docker volume rm $VOLUMES || true - fi - NETWORKS=$(docker network ls --filter "label=org.fiware=tutorial" -q) - if [[ -n $NETWORKS ]]; then - echo "Removing tutorial networks" - docker network rm $NETWORKS || true - fi -} - -addDatabaseIndex () { - printf "Adding appropriate \033[1mMongoDB\033[0m indexes for \033[1;34mOrion\033[0m ..." - docker exec db-mongo mongosh --eval ' - conn = new Mongo();db.createCollection("orion"); - db = conn.getDB("orion"); - db.createCollection("entities"); - db.entities.createIndex({"_id.servicePath": 1, "_id.id": 1, "_id.type": 1}, {unique: true}); - db.entities.createIndex({"_id.type": 1}); - db.entities.createIndex({"_id.id": 1});' > /dev/null -} - - -waitForMongo () { - echo -e "\n⏳ Waiting for \033[1mMongoDB\033[0m to be available\n" - while ! [ `docker inspect --format='{{.State.Health.Status}}' db-mongo` == "healthy" ] - do - sleep 1 - done -} - -waitForOrion () { - echo -e "\n⏳ Waiting for \033[1;34mOrion\033[0m to be available\n" - - while ! [ `docker inspect --format='{{.State.Health.Status}}' fiware-orion` == "healthy" ] - do - echo -e "Context Broker HTTP state: " `curl -s -o /dev/null -w %{http_code} 'http://localhost:1026/version'` " (waiting for 200)" - sleep 1 - done -} - -command="$1" -case "${command}" in - "help") - echo "usage: services [create|start|stop]" - ;; - "start") - export $(cat .env | grep "#" -v) - stoppingContainers - echo -e "Starting containers: \033[1;34mOrion\033[0m and a \033[1mMongoDB\033[0m database." - echo -e "- \033[1;34mOrion\033[0m is the context broker" - echo "" - ${dockerCmd} up -d --remove-orphans - waitForMongo - addDatabaseIndex - waitForOrion - loadData - displayServices - ;; - "stop") - export $(cat .env | grep "#" -v) - stoppingContainers - ;; - "create") - export $(cat .env | grep "#" -v) - echo "Pulling Docker images" - docker pull -q quay.io/curl/curl - ${dockerCmd} pull --ignore-pull-failures - ;; - *) - echo "Command not Found." - echo "usage: services [create|start|stop]" - exit 127; - ;; -esac \ No newline at end of file +echo -e "Checkout the \033[1;36mNGSI-v2\033[0m branch of this repository to run the Smart Supermarket tutorial.\n" +echo -e "Checkout the \033[1;31mNGSI-LD\033[0m branch of this repository to run the Smart Farm tutorial.\n"