|
| 1 | += Writing and updating data in TypeDB |
| 2 | +:keywords: typedb, typeql, tutorial, console, crud |
| 3 | +:pageTitle: |
| 4 | +:summary: |
| 5 | +:page-toclevels: 2 |
| 6 | +:tabs-sync-option: |
| 7 | +:test-typeql: linear |
| 8 | + |
| 9 | +== Overview |
| 10 | + |
| 11 | +This tutorial covers the basics of writing and updating data in TypeDB. |
| 12 | + |
| 13 | +== Prerequisites |
| 14 | + |
| 15 | +This tutorial assumes you have access to a running TypeDB instance, as well as a TypeDB Console. |
| 16 | + |
| 17 | +We recommend xref:{page-version}@home::install/ce.adoc[installing TypeDB Community Edition] as it is distributed bundled with Console for easy setup. |
| 18 | + |
| 19 | +This is a continuation of xref:{page-version}@tutorials::pipelines-read.adoc[], though you don't need to have completed it to follow along. |
| 20 | + |
| 21 | +== Example schema and data |
| 22 | + |
| 23 | +IMPORTANT: TODO PERMALINKS TO `typedb/typedb-examples` |
| 24 | + |
| 25 | +We are using the https://github.com/typedb/typedb-examples/tree/master/use-cases/bookstore[bookstore example] schema and data throughout this tutorial. |
| 26 | +You can load the example into your TypeDB instance using the following Console command: |
| 27 | + |
| 28 | +[,console] |
| 29 | +---- |
| 30 | +database create-init bookstore http://github.com/typedb/typedb-examples/releases/latest/download/bookstore-schema.tql http://github.com/typedb/typedb-examples/releases/latest/download/bookstore-data.tql |
| 31 | +---- |
| 32 | + |
| 33 | +.Full schema and data queries |
| 34 | +[%collapsible] |
| 35 | +==== |
| 36 | +[,typeql] |
| 37 | +---- |
| 38 | +#!test[schema, commit] |
| 39 | +include::{page-version}@academy::attachment$bookstore-schema.tql[lines=20..] |
| 40 | +---- |
| 41 | +[,typeql] |
| 42 | +---- |
| 43 | +#!test[write, commit] |
| 44 | +include::{page-version}@academy::attachment$bookstore-data.tql[lines=18..] |
| 45 | +---- |
| 46 | +==== |
| 47 | + |
| 48 | +== Add a book to the database with `insert` |
| 49 | + |
| 50 | +To add a new book to the database, we can use an xref:{page-version}@typeql-reference::pipelines/insert.adoc[`insert`] query. |
| 51 | +Simply use an xref:{page-version}@typeql-reference::statements/isa.adoc[`isa`] statement to specify the type of the entity, and then use |
| 52 | +xref:{page-version}@typeql-reference::statements/has.adoc[`has`] statements to list the attributes of the book. |
| 53 | + |
| 54 | +[,typeql] |
| 55 | +---- |
| 56 | +#!test[write, count = 1, rollback] |
| 57 | +insert |
| 58 | + $book isa paperback, |
| 59 | + has isbn-13 "9780441569595", |
| 60 | + has isbn-10 "0441569595", |
| 61 | + has title "Neuromancer", |
| 62 | + has page-count 288, |
| 63 | + has price 6.99, |
| 64 | + has genre "fiction", |
| 65 | + has genre "science fiction", |
| 66 | + has stock 5; |
| 67 | +---- |
| 68 | + |
| 69 | +Adding the author is as simple as inserting a `contributor` entity in a similar fashion, and an `authoring` relation linking the two. |
| 70 | + |
| 71 | +[,typeql] |
| 72 | +---- |
| 73 | +#!test[write, count = 1, commit] |
| 74 | +insert |
| 75 | + $book isa paperback, |
| 76 | + has isbn-13 "9780441569595", |
| 77 | + has isbn-10 "0441569595", |
| 78 | + has title "Neuromancer", |
| 79 | + has page-count 288, |
| 80 | + has price 6.99, |
| 81 | + has genre "fiction", |
| 82 | + has genre "science fiction", |
| 83 | + has stock 5; |
| 84 | + $author isa contributor, |
| 85 | + has name "Gibson, William"; |
| 86 | + (work: $book, author: $author) isa authoring; |
| 87 | +---- |
| 88 | + |
| 89 | +What if the author already exists? |
| 90 | +The query above would then merrily insert another `contributor` with the same name, which is almost certainly not what we intend. |
| 91 | + |
| 92 | +Thankfully, the fix is straightforward. |
| 93 | +We can use a xref:{page-version}@typeql-reference::pipelines/match.adoc[`match`] stage to find the author, and then use an xref:{page-version}@typeql-reference::pipelines/insert.adoc[`insert`] stage |
| 94 | +to create the book and the authoring relation. |
| 95 | + |
| 96 | +[,typeql] |
| 97 | +---- |
| 98 | +#!test[write, count = 1, rollback] |
| 99 | +match |
| 100 | + $author isa contributor, |
| 101 | + has name "Adams, Douglas"; |
| 102 | +insert |
| 103 | + $book isa paperback, |
| 104 | + has isbn-13 "9781529034585", |
| 105 | + has isbn-10 "1529034582", |
| 106 | + has title "Dirk Gently's Holistic Detective Agency", |
| 107 | + has page-count 288, |
| 108 | + has price 5.99, |
| 109 | + has genre "fiction", |
| 110 | + has genre "science fiction", |
| 111 | + has stock 4; |
| 112 | + (work: $book, author: $author) isa authoring; |
| 113 | +---- |
| 114 | + |
| 115 | +== Insert an author only if one doesn't exist with `put` |
| 116 | + |
| 117 | +We happened to know that an author named "Adams, Douglas" was already present in the database. |
| 118 | +What if we didn't know that, but still wanted to avoid inserting a duplicate author? |
| 119 | +We can use a xref:{page-version}@typeql-reference::pipelines/put.adoc[`put`] clause to insert the author only if a `contributor` matching the constraints does not already exist in the database. |
| 120 | + |
| 121 | +[,typeql] |
| 122 | +---- |
| 123 | +#!test[write, count = 1, rollback] |
| 124 | +put |
| 125 | + $author isa contributor, |
| 126 | + has name "Adams, Douglas"; |
| 127 | +insert |
| 128 | + $book isa paperback, |
| 129 | + has isbn-13 "9781529034585", |
| 130 | + has isbn-10 "1529034582", |
| 131 | + has title "Dirk Gently's Holistic Detective Agency", |
| 132 | + has page-count 288, |
| 133 | + has price 5.99, |
| 134 | + has genre "fiction", |
| 135 | + has genre "science fiction", |
| 136 | + has stock 4; |
| 137 | + (work: $book, author: $author) isa authoring; |
| 138 | +---- |
| 139 | + |
| 140 | +[TIP] |
| 141 | +==== |
| 142 | +It might be tempting to combine all of the above into one `put` query: |
| 143 | +
|
| 144 | +[,typeql] |
| 145 | +---- |
| 146 | +#!test[write, count = 1, rollback] |
| 147 | +put |
| 148 | + $author isa contributor, |
| 149 | + has name "Adams, Douglas"; |
| 150 | + $book isa paperback, |
| 151 | + has isbn-13 "9781529034585", |
| 152 | + has isbn-10 "1529034582", |
| 153 | + has title "Dirk Gently's Holistic Detective Agency", |
| 154 | + has page-count 288, |
| 155 | + has price 5.99, |
| 156 | + has genre "fiction", |
| 157 | + has genre "science fiction", |
| 158 | + has stock 4; |
| 159 | + (work: $book, author: $author) isa authoring; |
| 160 | +---- |
| 161 | +
|
| 162 | +It's important to remember that if anything in the `put` fails to match existing data, the entirety of `put` body is inserted. |
| 163 | +If the author already exists, but the book doesn't, a new entity for the author is inserted alongside the book. |
| 164 | +This is why it's important to keep `put` stages as short as possible, usually one per object. |
| 165 | +Here's an example with multiple ``put``s: |
| 166 | +
|
| 167 | +[,typeql] |
| 168 | +---- |
| 169 | +#!test[write, count = 1, rollback] |
| 170 | +put |
| 171 | + $author isa contributor, |
| 172 | + has name "Adams, Douglas"; |
| 173 | +put |
| 174 | + $publisher isa publisher, |
| 175 | + has name "Signet"; |
| 176 | +insert |
| 177 | + $book isa paperback, |
| 178 | + has isbn-13 "9781529034585", |
| 179 | + has isbn-10 "1529034582", |
| 180 | + has title "Dirk Gently's Holistic Detective Agency", |
| 181 | + has page-count 288, |
| 182 | + has price 5.99, |
| 183 | + has genre "fiction", |
| 184 | + has genre "science fiction", |
| 185 | + has stock 4; |
| 186 | + (work: $book, author: $author) isa authoring; |
| 187 | + (publisher: $publisher, published: $book) isa publishing; |
| 188 | +---- |
| 189 | +==== |
| 190 | + |
| 191 | +== Update stock with `update` |
| 192 | + |
| 193 | +When we sell a book, we need to decrease the stock by one. |
| 194 | +Concretely, that means deleting the old `stock` attribute and inserting a new one with the updated value. |
| 195 | + |
| 196 | +[,typeql] |
| 197 | +---- |
| 198 | +#!test[write, count = 1, commit] |
| 199 | +match |
| 200 | + $book isa book, has isbn-13 "9780671461492", has stock $stock; |
| 201 | + let $new-stock = $stock - 1; |
| 202 | +delete |
| 203 | + has $stock of $book; |
| 204 | +insert |
| 205 | + $book has stock == $new-stock; |
| 206 | +---- |
| 207 | + |
| 208 | +xref:{page-version}@typeql-reference::pipelines/update.adoc[`update`] is a shorthand for the above. |
| 209 | + |
| 210 | +[,typeql] |
| 211 | +---- |
| 212 | +#!test[write, count = 1, commit] |
| 213 | +match |
| 214 | + $book isa book, has isbn-13 "9780671461492", has stock $stock; |
| 215 | + let $new-stock = $stock - 1; |
| 216 | +update |
| 217 | + $book has stock == $new-stock; |
| 218 | +---- |
| 219 | + |
| 220 | +[TIP] |
| 221 | +==== |
| 222 | +`update` is only allowed when the cardinality constraint of the attribute is at most one. |
| 223 | +This is to avoid ambiguity: there's at most one old attribute to delete. |
| 224 | +
|
| 225 | +By default, all attributes have cardinality `0..1`, but if you define an attribute ownership with higher cardinality, you will not be able to use `update` even if the object happens to only have zero |
| 226 | +or one attribute of the type. |
| 227 | +==== |
| 228 | + |
| 229 | +== Delete a book with `delete` |
| 230 | + |
| 231 | +To delete a book, we can use a xref:{page-version}@typeql-reference::pipelines/delete.adoc[`delete`] query. |
| 232 | + |
| 233 | +[,typeql] |
| 234 | +---- |
| 235 | +#!test[write, count = 1, rollback] |
| 236 | +match |
| 237 | + $book isa book, has isbn-13 "9780671461492"; |
| 238 | +delete |
| 239 | + $book; |
| 240 | +---- |
| 241 | + |
| 242 | +Note that while this query deletes all attributes of the book, it does not delete the relations in which the book is involved. |
| 243 | +The book is deleted _from_ the relations, but the relations themselves remain. |
| 244 | + |
| 245 | +To delete all relations in which the book is involved as well as the book, we need to match them first: |
| 246 | + |
| 247 | +[,typeql] |
| 248 | +---- |
| 249 | +#!test[write, count = 3, commit] |
| 250 | +match |
| 251 | + $book isa book, has isbn-13 "9780671461492"; |
| 252 | + $rel links ($book); |
| 253 | +delete |
| 254 | + $rel; |
| 255 | + $book; |
| 256 | +---- |
| 257 | + |
| 258 | +== Further reading |
| 259 | + |
| 260 | +[cols-2] |
| 261 | +-- |
| 262 | +.xref:{page-version}@tutorials::pipelines-advanced.adoc[] |
| 263 | +[.clickable] |
| 264 | +**** |
| 265 | +Learn about complex pipelines in the next tutorial |
| 266 | +**** |
| 267 | + |
| 268 | +.xref:{page-version}@core-concepts::typeql/index.adoc[] |
| 269 | +[.clickable] |
| 270 | +**** |
| 271 | +TypeQL core concepts |
| 272 | +**** |
| 273 | + |
| 274 | +.xref:{page-version}@typeql-reference::index.adoc[] |
| 275 | +[.clickable] |
| 276 | +**** |
| 277 | +TypeQL reference manual |
| 278 | +**** |
| 279 | +-- |
0 commit comments