# ArangoDB hands-on session 2 with example solutions to exercises The previous hands-on session's model solutions: https://hackmd.io/@valterUo/ByPof7cMO ## Exercises 2 The documentation is useful: https://www.arangodb.com/docs/stable/index.html. 1. Write a query that filters based on SHA1 and SHA256 hashes. Then create a persistent index that is based on both of these attributes. Compare how much faster the query is with or without the index. How does it affect that the index is combined of two attributes? Is there a difference if your FILTER clause contains `AND` or `OR`. (1 point) ```javascript FOR package IN packages FILTER package.SHA1 == "dbb1343a3d24f60e5038994e3528dd7486e40943" AND package.SHA256 == "c1fad54e790d69b83f32f2612963baba3ea8091ff3ca72c960c7312096223e3a" RETURN package db.packages.ensureIndex({ type: "persistent", fields: [ "SHA1", "SHA256" ], unique: false }) ``` 2. Create a full-text index on the attribute `Description`. Query those packages whose descriptions contain 'Python'. Group the result by architecture and return the count of packages for each architecture type. The result can look something like `[{"architecture": x, "number_of_packages": y}, ...]` (2 points) ```javascript db.packages.ensureIndex({ type: "fulltext", fields: [ "Description" ], minLength: 3 }) FOR package IN FULLTEXT(packages, "Description", "Python") COLLECT architecture = package.Architecture INTO package_group RETURN { "architecture": architecture, "number_of_packages": count(package_group) } ``` 3. Create an index on the attribute `Size`. Query packages whose sizes are between x and y and sort the result to ascending order (the smaller first). (1 point) ``` db.packages.ensureIndex({ type: "persistent", fields: [ "Size" ], unique: false }) FOR package IN packages FILTER TO_NUMBER(package.Size) < 1000 AND TO_NUMBER(package.Size) > 50 SORT package.Size ASC RETURN package ``` 5. Write a transaction that inserts the following data into `packages` collection if it does not already exist. In the case it exists, throw a proper error. (1 point) ```javascript { "_id": "packages/elinks-data", "_rev": "_cDljlvG---", "_key": "elinks-data", "Architecture": "all", "Description": "advanced text-mode WWW browser - data files", "Filename": "pool/main/e/elinks/elinks-data_0.12~pre6-5_all.deb", "Maintainer": "Moritz Muehlenhoff <jmm@debian.org>", "Package": "elinks-data", "Priority": "optional", "SHA1": "4ec9dbb32065b80ae5bc9d3f6d53edd499caf74a", "SHA256": "9dbeaaadb9d69bb1bceb183bfda4f8f87e4d4a2f10dd2e2da95827c1f7c4a55c", "Section": "web", "Size": "389458", "Source": "elinks", "Tag": "role::app-data", "Version": "0.12~pre6-5", "InstalledSize": 1733 } ``` It is questionable if it is good to overwrite ArangoDB errors like this. Anyway, it is good to keep in mind that you can throw your own errors at any point. Also, remember that you can use Javascript here (try-catch). ```javascript db._executeTransaction({ collections: { write: "packages" }, action: function () { var db = require("@arangodb").db let new_data = { "_id": "packages/elinks-data", "_rev": "_cDljlvG---", "_key": "elinks-data", "Architecture": "all", "Description": "advanced text-mode WWW browser - data files", "Filename": "pool/main/e/elinks/elinks-data_0.12~pre6-5_all.deb", "Maintainer": "Moritz Muehlenhoff <jmm@debian.org>", "Package": "elinks-data", "Priority": "optional", "SHA1": "4ec9dbb32065b80ae5bc9d3f6d53edd499caf74a", "SHA256": "9dbeaaadb9d69bb1bceb183bfda4f8f87e4d4a2f10dd2e2da95827c1f7c4a55c", "Section": "web", "Size": "389458", "Source": "elinks", "Tag": "role::app-data", "Version": "0.12~pre6-5", "InstalledSize": 1733 } try { db.packages.save(new_data) } catch(err) { if(err.error_num = 1210) { throw "doh! Document already exists!" } else { throw err } } } }) ``` 7. Query some packages returning their `Installed-Size` attributes using the recommended `package.Installed-Size` notation. What happens? In this case, you can use the notation `package["Installed-Size"]` but of course, the attribute `Installed-Size` is not good. Write a query that updates all `Installed-Size` attributes to `InstalledSize` attributes and removes `Installed-Size` key-value pairs from the documents. Because you want to be sure that no data are lost during the update and the output is correct, perform this update using transactions. Besides update query, write a query or queries that check the correctness of the update. If your update fails for some reason, you can abort the transaction and roll-back. Hint: You benefit from https://www.arangodb.com/docs/stable/aql/operations-update.html. (2 points) ```javascript db._executeTransaction({ collections: { read: "packages", write: "packages" }, action: function () { var db = require("@arangodb").db // Query amount of documents with Installed-Size attribute const c = db._query("FOR doc in packages FILTER HAS(doc, 'Installed-Size') == true COLLECT WITH COUNT INTO length RETURN length") const count_before_update = c._documents[0] // Perform the update db._query("FOR package IN packages UPDATE package WITH { 'InstalledSize': package['Installed-Size'], 'Installed-Size': null } IN packages OPTIONS { keepNull: false }") // Count updated documents const e = db._query("FOR doc in packages FILTER HAS(doc, 'InstalledSize') == true COLLECT WITH COUNT INTO length RETURN length") const count_after_update = e._documents[0] // If the numbers of updated documents do not match, throw exception and roll-back if (count_before_update != count_after_update) { throw "Fail in update" } else { return "OK" } } }) ```