diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index 7847624f..1e0114a4 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -2,7 +2,7 @@ * xref:hello-world:start-using-sdk.adoc[Hello World] ** xref:hello-world:sample-application.adoc[] -// ** xref:hello-world:student-record-developer-tutorial.adoc[] +** xref:hello-world:student-record-developer-tutorial.adoc[Student Record Tutorial] ** xref:howtos:managing-connections.adoc[Connecting to Your Database] *** xref:howtos:sdk-authentication.adoc[Authentication & Authorization] *** xref:howtos:troubleshooting-cloud-connections.adoc[Troubleshooting Cloud Connections] diff --git a/modules/devguide/examples/java/AddEnrollments.java b/modules/devguide/examples/java/AddEnrollments.java new file mode 100644 index 00000000..66e66b68 --- /dev/null +++ b/modules/devguide/examples/java/AddEnrollments.java @@ -0,0 +1,102 @@ +import com.couchbase.client.core.error.CouchbaseException; +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.Collection; +import com.couchbase.client.java.Scope; +import com.couchbase.client.java.json.JsonArray; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.query.QueryOptions; +import com.couchbase.client.java.query.QueryResult; +import com.couchbase.client.java.query.QueryScanConsistency; +import com.couchbase.client.java.ClusterOptions; + +import java.time.Duration; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +public class AddEnrollments { + + public static void main(String[] args) { + + String connectionString = "<>"; // Replace this with Connection String + String username = "<>"; // Replace this with username from cluster access credentials + String password = "<>"; // Replace this with password from cluster access credentials + + Cluster cluster = Cluster.connect(connectionString, ClusterOptions.clusterOptions(username, password) + .environment(env -> env.applyProfile("wan-development")) + ); + + // Retrieves the student bucket you set up. + Bucket bucket = cluster.bucket("student-bucket"); + + // Forces the application to wait until the bucket is ready. + bucket.waitUntilReady(Duration.ofSeconds(10)); + + // Retrieves the `art-school-scope` collection from the scope. + Scope scope = bucket.scope("art-school-scope"); + Collection student_records = scope.collection("student-record-collection"); + + // Retrieves Hilary's student record, the `graphic design` course record, and the `art history` course record. + // Each method uses a SQL++ call to retrieve a single record from each collection. + JsonObject hilary = retrieveStudent(cluster,"Hilary Smith"); + JsonObject graphic_design = retrieveCourse(cluster, "graphic design"); + JsonObject art_history = retrieveCourse(cluster, "art history"); + + // Couchbase does not have a native date type, so the common practice is to store dates as strings. + String currentDate = LocalDate.now().format(DateTimeFormatter.ISO_DATE); + + // Stores the `enrollments` inside the student record as an array. + // `JsonArray.create()` creates an empty list structure. + JsonArray enrollments = JsonArray.create(); + + // Adds two JSON elements to the `enrollments` array: the course that the enrollment relates to, and the date that the student enrolled in the course. + // To avoid repeating data all over the cluster, you store a reference to the course instead of the entire course record itself in this field. + // This means that you do not have to search through every single record if the course details change. + enrollments.add(JsonObject.create() + .put("course-id", graphic_design.getString("id")) + .put("date-enrolled", currentDate)); + enrollments.add(JsonObject.create() + .put("course-id", art_history.getString("id")) + .put("date-enrolled", currentDate)); + + // Adds the `enrollments` array to Hilary's student record. + hilary.put("enrollments", enrollments); + + // Commits the changes to the collection. + // The `upsert` function call takes the key of the record you want to insert or update and the record itself as parameters. + // If the `upsert` call finds a document with a matching ID in the collection, it updates the document. + // If there is no matching ID, it creates a new document. + student_records.upsert(hilary.getString("id"), hilary); + + cluster.disconnect(); + + } + + private static JsonObject retrieveStudent(Cluster cluster, String name) throws CouchbaseException { + + QueryOptions studentQueryOptions = QueryOptions.queryOptions(); + studentQueryOptions.parameters(JsonObject.create().put("name", name)); + studentQueryOptions.scanConsistency(QueryScanConsistency.REQUEST_PLUS); + + final QueryResult result = cluster.query("select META().id, src.* " + + "from `student-bucket`.`art-school-scope`.`student-record-collection` src " + + "where src.`name` = $name", studentQueryOptions); + + return result.rowsAsObject().get(0); + + } + + private static JsonObject retrieveCourse(Cluster cluster, String course) throws CouchbaseException { + + QueryOptions courseQueryOptions = QueryOptions.queryOptions(); + courseQueryOptions.parameters(JsonObject.create().put("courseName", course)); + courseQueryOptions.scanConsistency(QueryScanConsistency.REQUEST_PLUS); + + final QueryResult result = cluster.query("select META().id, crc.* " + + "from `student-bucket`.`art-school-scope`.`course-record-collection` crc " + + "where crc.`course-name` = $courseName", courseQueryOptions); + + return result.rowsAsObject().get(0); + + } +} \ No newline at end of file diff --git a/modules/devguide/examples/java/ArtSchoolRetriever.java b/modules/devguide/examples/java/ArtSchoolRetriever.java new file mode 100644 index 00000000..af2d2465 --- /dev/null +++ b/modules/devguide/examples/java/ArtSchoolRetriever.java @@ -0,0 +1,48 @@ +import com.couchbase.client.core.error.CouchbaseException; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.query.QueryOptions; +import com.couchbase.client.java.query.QueryResult; +import com.couchbase.client.java.ClusterOptions; + +public class ArtSchoolRetrieverParameters { + + public static void main(String[] args) { + + String connectionString = "<>"; // Replace this with Connection String + String username = "<>"; // Replace this with username from cluster access credentials + String password = "<>"; // Replace this with password from cluster access credentials + + Cluster cluster = Cluster.connect(connectionString, ClusterOptions.clusterOptions(username, password) + .environment(env -> env.applyProfile("wan-development")) + ); + + + retrieveCourses(cluster); + + cluster.disconnect(); + } + + private static void retrieveCourses(Cluster cluster) { + + try { + + // This SQL++ statement takes the parameter `$creditPopints`, + // which is then substituted by the value in the second parameter when the statement is called. + final QueryResult result = cluster.query("select crc.* " + + "from `student-bucket`.`art-school-scope`.`course-record-collection` crc " + + "where crc.`credit-points` < $creditPoints", + + // The second parameter in the function call, with a value that replaces `$creditPoints`. + QueryOptions.queryOptions() + .parameters(JsonObject.create().put("creditPoints", 200))); + + for (JsonObject row : result.rowsAsObject()) { + System.out.println("Found row: " + row); + } + + } catch (CouchbaseException ex) { + ex.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/modules/devguide/examples/java/ArtSchoolRetrieverAll.java b/modules/devguide/examples/java/ArtSchoolRetrieverAll.java new file mode 100644 index 00000000..673c5275 --- /dev/null +++ b/modules/devguide/examples/java/ArtSchoolRetrieverAll.java @@ -0,0 +1,37 @@ +import com.couchbase.client.core.error.CouchbaseException; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.query.QueryResult; +import com.couchbase.client.java.ClusterOptions; + +public class ArtSchoolRetriever { + + public static void main(String[] args) { + + String connectionString = "<>"; // Replace this with Connection String + String username = "<>"; // Replace this with username from cluster access credentials + String password = "<>"; // Replace this with password from cluster access credentials + + Cluster cluster = Cluster.connect(connectionString, ClusterOptions.clusterOptions(username, password) + .environment(env -> env.applyProfile("wan-development")) + ); + + retrieveCourses(cluster); + + cluster.disconnect(); + } + + private static void retrieveCourses(Cluster cluster) { + + try { + final QueryResult result = cluster.query("select crc.* from `student-bucket`.`art-school-scope`.`course-record-collection` crc"); + + for (JsonObject row : result.rowsAsObject()) { + System.out.println("Found row: " + row); + } + + } catch (CouchbaseException ex) { + ex.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/modules/devguide/examples/java/ConnectStudent.java b/modules/devguide/examples/java/ConnectStudent.java new file mode 100644 index 00000000..ea2eb26f --- /dev/null +++ b/modules/devguide/examples/java/ConnectStudent.java @@ -0,0 +1,47 @@ +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.Collection; +import com.couchbase.client.java.Scope; +import com.couchbase.client.java.ClusterOptions; +import java.time.Duration; + +public class ConnectStudent { + + public static void main(String[] args) { + + String connectionString = "<>"; // Replace this with Connection String + String username = "<>"; // Replace this with username from cluster access credentials + String password = "<>"; // Replace this with password from cluster access credentials + + //Connecting to the cluster + Cluster cluster = Cluster.connect(connectionString, ClusterOptions.clusterOptions(username, password) + // Use the pre-configured profile below to avoid latency issues with your connection. + .environment(env -> env.applyProfile("wan-development")) + ); + + // The `cluster.bucket` retrieves the bucket you set up for the student cluster. + Bucket bucket = cluster.bucket("student-bucket"); + + // Most of the Couchbase APIs are non-blocking. + // When you call one of them, your application carries on and continues to perform other actions while the function you called executes. + // When the function has finished executing, it sends a notification to the caller and the output of the call is processed. + // While this usually works, in this code sample the application carries on without waiting for the bucket retrieval to complete after you make the call to `cluster.bucket`. + // This means that you now have to try to retrieve the scope from a bucket object that has not been fully initialized yet. + // To fix this, you can use the `waitUntilReady` call. + // This call forces the application to wait until the bucket object is ready. + bucket.waitUntilReady(Duration.ofSeconds(10)); + + // The `bucket.scope` retrieves the `art-school-scope` from the bucket. + Scope scope = bucket.scope("art-school-scope"); + + // The `scope.collection` retrieves the student collection from the scope. + Collection student_records = scope.collection("student-record-collection"); + + // A check to make sure the collection is connected and retrieved when you run the application. + // You can see the output using maven. + System.out.println("The name of this collection is " + student_records.name()); + + // Like with all database systems, it's good practice to disconnect from the Couchbase cluster after you have finished working with it. + cluster.disconnect(); + } +} \ No newline at end of file diff --git a/modules/devguide/examples/java/InsertCourses.java b/modules/devguide/examples/java/InsertCourses.java new file mode 100644 index 00000000..e923fbb4 --- /dev/null +++ b/modules/devguide/examples/java/InsertCourses.java @@ -0,0 +1,47 @@ +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.Collection; +import com.couchbase.client.java.Scope; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.ClusterOptions; + +import java.time.Duration; + +public class InsertCourses { + + public static void main(String[] args) { + + String connectionString = "<>"; // Replace this with Connection String + String username = "<>"; // Replace this with username from cluster access credentials + String password = "<>"; // Replace this with password from cluster access credentials + + Cluster cluster = Cluster.connect(connectionString, ClusterOptions.clusterOptions(username, password) + .environment(env -> env.applyProfile("wan-development")) + ); + + Bucket bucket = cluster.bucket("student-bucket"); + bucket.waitUntilReady(Duration.ofSeconds(10)); + Scope scope = bucket.scope("art-school-scope"); + + // The code here is similar to creating a student record, but it writes to a different collection. + Collection course_records = scope.collection("course-record-collection"); + + addCourse(course_records, "ART-HISTORY-000001", "art history", "fine art", 100); + addCourse(course_records, "FINE-ART-000002", "fine art", "fine art", 50); + addCourse(course_records, "GRAPHIC-DESIGN-000003", "graphic design", "media and communication", 200); + + cluster.disconnect(); + } + + private static void addCourse(Collection collection, String id, String name, + String faculty, int creditPoints) { + + JsonObject course = JsonObject.create() + .put("course-name", name) + .put("faculty", faculty) + .put("credit-points", creditPoints); + + collection.upsert(id, course); + + } +} \ No newline at end of file diff --git a/modules/devguide/examples/java/InsertStudent.java b/modules/devguide/examples/java/InsertStudent.java new file mode 100644 index 00000000..ebee4641 --- /dev/null +++ b/modules/devguide/examples/java/InsertStudent.java @@ -0,0 +1,44 @@ +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.Collection; +import com.couchbase.client.java.Scope; +import com.couchbase.client.java.json.JsonObject; +import com.couchbase.client.java.ClusterOptions; + +import java.time.Duration; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +public class InsertStudent { + + public static void main(String[] args) { + + String connectionString = "<>"; // Replace this with Connection String + String username = "<>"; // Replace this with username from cluster access credentials + String password = "<>"; // Replace this with password from cluster access credentials + + Cluster cluster = Cluster.connect(connectionString, ClusterOptions.clusterOptions(username, password) + .environment(env -> env.applyProfile("wan-development")) + ); + + Bucket bucket = cluster.bucket("student-bucket"); + bucket.waitUntilReady(Duration.ofSeconds(10)); + Scope scope = bucket.scope("art-school-scope"); + Collection student_records = scope.collection("student-record-collection"); + + // This `JsonObject` class creates and populates the student record. + JsonObject hilary = JsonObject.create() + .put("name", "Hilary Smith") + .put("date-of-birth", + LocalDate.of(1980, 12, 21) + .format(DateTimeFormatter.ISO_DATE)); + + // The `upsert` function inserts or updates documents in a collection. + // The first parameter is a unique ID for the document, similar to a primary key used in a relational database system. + // If the `upsert` call finds a document with a matching ID in the collection, it updates the document. + // If there is no matching ID, it creates a new document. + student_records.upsert("000001", hilary); + + cluster.disconnect(); + } +} \ No newline at end of file diff --git a/modules/hello-world/assets/images/add-allowed-ip.png b/modules/hello-world/assets/images/add-allowed-ip.png new file mode 100644 index 00000000..44cbdfc7 Binary files /dev/null and b/modules/hello-world/assets/images/add-allowed-ip.png differ diff --git a/modules/hello-world/assets/images/create-cluster-credentials.png b/modules/hello-world/assets/images/create-cluster-credentials.png new file mode 100644 index 00000000..c82d0e86 Binary files /dev/null and b/modules/hello-world/assets/images/create-cluster-credentials.png differ diff --git a/modules/hello-world/assets/images/new-course-records.png b/modules/hello-world/assets/images/new-course-records.png new file mode 100644 index 00000000..a31c31a4 Binary files /dev/null and b/modules/hello-world/assets/images/new-course-records.png differ diff --git a/modules/hello-world/assets/images/new-student-record.png b/modules/hello-world/assets/images/new-student-record.png new file mode 100644 index 00000000..bc88a08f Binary files /dev/null and b/modules/hello-world/assets/images/new-student-record.png differ diff --git a/modules/hello-world/assets/images/query-editor-filters.png b/modules/hello-world/assets/images/query-editor-filters.png new file mode 100644 index 00000000..676dad57 Binary files /dev/null and b/modules/hello-world/assets/images/query-editor-filters.png differ diff --git a/modules/hello-world/assets/images/record-retrieval-console-output.png b/modules/hello-world/assets/images/record-retrieval-console-output.png new file mode 100644 index 00000000..900b831a Binary files /dev/null and b/modules/hello-world/assets/images/record-retrieval-console-output.png differ diff --git a/modules/hello-world/assets/images/record-retrieval-parameters-console-output.png b/modules/hello-world/assets/images/record-retrieval-parameters-console-output.png new file mode 100644 index 00000000..fba8d7cb Binary files /dev/null and b/modules/hello-world/assets/images/record-retrieval-parameters-console-output.png differ diff --git a/modules/hello-world/assets/images/student-record-collection-console-output.png b/modules/hello-world/assets/images/student-record-collection-console-output.png new file mode 100644 index 00000000..d8d2f270 Binary files /dev/null and b/modules/hello-world/assets/images/student-record-collection-console-output.png differ diff --git a/modules/hello-world/assets/images/updated-student-record.png b/modules/hello-world/assets/images/updated-student-record.png new file mode 100644 index 00000000..d3ddf0db Binary files /dev/null and b/modules/hello-world/assets/images/updated-student-record.png differ diff --git a/modules/hello-world/pages/overview.adoc b/modules/hello-world/pages/overview.adoc index 1bf03464..120abb24 100644 --- a/modules/hello-world/pages/overview.adoc +++ b/modules/hello-world/pages/overview.adoc @@ -112,10 +112,10 @@ How-to guides to help you start your development journey with Couchbase and the [.column] .Easy to Connect & Get Started -* xref:hello-world:start-using-sdk.adoc[Quickstart Guide] +* xref:hello-world:start-using-sdk.adoc[Getting Started] * xref:hello-world:sample-application.adoc[] +* xref:hello-world:student-record-developer-tutorial.adoc[Beginners' Couchbase Tutorial] * xref:howtos:managing-connections.adoc[] -// * xref:hello-world:student-record-developer-tutorial.adoc[Beginners' Couchbase Tutorial] [.column] .Search, Query, Analyze diff --git a/modules/hello-world/pages/platform-help.adoc b/modules/hello-world/pages/platform-help.adoc index 94530490..8c921ef6 100644 --- a/modules/hello-world/pages/platform-help.adoc +++ b/modules/hello-world/pages/platform-help.adoc @@ -39,7 +39,7 @@ SDKMAN! -- the Software Development Kit Manager -- enables multiple Java version This third party tool is unnecessary in most production environments, but ideal for development machines. Installation instructions can be found on the https://sdkman.io/install[SDKMAN! website]. -Once SDKMAN! is installed, use it to install the latest version of Scala 2.13: +Once SDKMAN! is installed, use it to install the latest version of Java: [source,console] ---- diff --git a/modules/hello-world/pages/start-using-sdk.adoc b/modules/hello-world/pages/start-using-sdk.adoc index 171897e0..c49c8eb5 100644 --- a/modules/hello-world/pages/start-using-sdk.adoc +++ b/modules/hello-world/pages/start-using-sdk.adoc @@ -42,6 +42,10 @@ We'll explore creating and retrieving data records in more detail < + + 4.0.0 + + org.example + couchbase-java + 1.0-SNAPSHOT + + + 16 + 16 + UTF-8 + ${encoding} + ${encoding} + ${encoding} + ${encoding} + + + + + + com.couchbase.client + java-client + {sdk_current_version} + + + org.slf4j + slf4j-api + 2.0.9 + + + org.slf4j + slf4j-simple + 2.0.9 + + + + +---- ++ +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and finish your SDK setup. + +Next, connect your Java SDK to your cluster. + + +[#connect-to-the-cluster] +=== Connect the SDK to Your Cluster + +To connect to the cluster: + +. In your `java` directory, create a new file called `ConnectStudent.java`. ++ +.... +📂 ~ (your home directory) + 📂 student + 📃 pom.xml + 📂 src + 📂 main + 📂 java + 📃 ConnectStudent.java ⬅ here! +.... ++ +. Paste the following code block into your `ConnectStudent.java` file: ++ +[source, java] +---- +include::devguide:example$java/ConnectStudent.java[] +---- + +. In the `ConnectStudent.java` file, replace the `\<>`, `\<>`, and `\<>` placeholders with the connection string, username, and password that you noted when configuring the cluster connection. ++ +[IMPORTANT] +==== +You must re-run `mvn install` in your `student` directory whenever you make a change to a java file to rebuild your application. +==== ++ +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and rebuild your application. +. Run the following command to check that the connection works: ++ +[source, console] +---- +mvn exec:java -Dexec.mainClass="ConnectStudent" -Dexec.cleanupDaemonThreads=false +---- ++ +If the connection is successful, the collection name outputs in the console log. ++ +image::student-record-collection-console-output.png[alt="Console showing successful connection to server"] + +If you come across errors in your console, see the <<#roubleshooting,troubleshooting section>>. + + + +== Create a Student Record + +After connecting to the cluster, you can create a student record in the form of a JSON document inserted into the `student-record-collection`. + +To create a student record: + +. In your `java` directory, create a new file called `InsertStudent.java`. +. Paste the following code block into your `InsertStudent.java` file: ++ +[source, java] +---- +include::devguide:example$java/InsertStudent.java[] +---- ++ +. In the `InsertStudent.java` file, replace the `\<>`, `\<>`, and `\<>` placeholders with the connection string, username, and password that you noted when configuring the cluster connection. +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and rebuild your application. +. Run the following command to insert the student record into the collection: ++ +[source, sh] +---- +mvn exec:java -Dexec.mainClass="InsertStudent" -Dexec.cleanupDaemonThreads=false +---- ++ +. From the Capella UI, go to your student cluster and check the `student-record-collection` for the new student record you just added: +.. Go to menu:Data Tools[Documents]. +.. Under *Get documents from*, select `student-bucket`, `art-school-scope`, and `student-record-collection`. +.. Click btn:[Get Documents]. ++ +image::new-student-record.png[alt="Student added to the student-record-collection in the cluster"] + + +=== Create Course Records + +Creating course records is similar to creating student records. +To create course records: + +. In your `java` directory, create a new file called `InsertCourses.java`. +. Paste the following code block into your `InsertCourses.java` file: ++ +[source, java] +---- +include::devguide:example$java/InsertCourses.java[] +---- ++ +. In the `InsertCourses.java` file, replace the `\<>`, `\<>`, and `\<>` placeholders with the connection string, username, and password that you noted when configuring the cluster connection. +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and rebuild your application. +. Run the following command to insert the student record into the collection: ++ +[source, sh] +---- +mvn exec:java -Dexec.mainClass="InsertCourses" -Dexec.cleanupDaemonThreads=false +---- ++ +. From the Capella UI, go to your student cluster and check the `course-record-collection` for the new course records you just added. ++ +image::new-course-records.png[alt="Courses added to the course-record-collection in the cluster"] + +If you come across errors in your console, see the <<#roubleshooting,troubleshooting section>>. + + + + +== Retrieve Records + +You can retrieve your records using the <<#retrieve-with-query-editor,query editor>> or the <<#retrieve-with-sdk,SDK>>. + +[#retrieve-with-query-editor] +=== Retrieving Records with the Query Editor + +To retrieve the records with the Query Editor, you must first define an index. + +==== Define an Index + +Before you can retrieve your records with the query editor, you must first define an index in your bucket. +The index helps your cluster find specific data when you run a query. + +To define an index: + +. On the *Operational Clusters* page, select *student-cluster*. + +. Go to menu:Data Tools[Query]. + +. Select *student-bucket* and *art-school-scope* in the *Context* drop-down. ++ +Using these filters, you can narrow down the scope of your queries. +You do not need to add the names of your bucket and scope to your queries. ++ +image::query-editor-filters.png[alt="Filters in the Query Editor"] ++ +. Enter the following query into your query editor: ++ +[source, sqlpp] +---- +CREATE PRIMARY INDEX course_idx ON `course-record-collection` +---- ++ +. Click btn:[Run] to create a single index called `course_idx` in your `course-record-collection`. + +==== Retrieve Your Records + +You can use the Query Editor to retrieve all course records at once, or narrow your search down to retrieve records based on specific criteria. + +===== Retrieve All Course Records + +To retrieve all of your course records using the query editor: + +. Enter the following query into your query editor: ++ +[source, sqlpp] +---- +SELECT crc.* FROM `course-record-collection` crc +---- ++ +. Click btn:[Run] to retrieve all course records. ++ +[source, json] +---- +[ + { + "course-name": "art history", + "credit-points": 100, + "faculty": "fine art" + }, + { + "course-name": "fine art", + "credit-points": 50, + "faculty": "fine art" + }, + { + "course-name": "graphic design", + "credit-points": 200, + "faculty": "media and communication" + } +] +---- + +===== Retrieve Course Records with Less than 200 Credits + +You can expand your query to narrow your search down further. +To retrieve only courses with less than 200 `credit-points` using the query editor: + +. Enter the following query into your query editor: ++ +[source, sqlpp] +---- +SELECT crc.* FROM `course-record-collection` crc WHERE crc.`credit-points` < 200 +---- ++ +. Click btn:[Run] to retrieve all courses with less than 200 credits. ++ +[source, json] +---- +[ + { + "course-name": "art history", + "credit-points": 100, + "faculty": "fine art" + }, + { + "course-name": "fine art", + "credit-points": 50, + "faculty": "fine art" + } +] +---- + +==== Retrieve Record IDs + +The `id` field is not automatically returned when you retrieve all of your course information. + +The `id` is part of a document's meta structure, and to retrieve it you must adjust your {sqlpp} query and run it again: + +. Enter the following query into your query editor: ++ +[source, sqlpp] +---- +SELECT META().id, crc.* FROM `course-record-collection` crc WHERE crc.`credit-points` < 200 +---- ++ +The `META()` function call returns any property contained inside the document's metadata, including the ID. ++ +. Click btn:[Run] to retrieve course records and their IDs. ++ +[source, json] +---- +[ + { + "course-name": "art history", + "credit-points": 100, + "faculty": "fine art", + "id": "ART-HISTORY-000001" + }, + { + "course-name": "fine art", + "credit-points": 50, + "faculty": "fine art", + "id": "FINE-ART-000002" + } +] +---- + + +[#retrieve-with-sdk] +=== Retrieving Records with the SDK + +You can also use {sqlpp} queries to retrieve your records with the SDK. +Unlike the query editor, you must include the name of the bucket and the scope to fully qualify the name of the collection in the {sqlpp} statement in your application. +For example: + +[source, sqlpp] +---- +SELECT crc.* FROM `student-bucket`.`art-school-scope`.`course-record-collection` crc +---- + +==== Retrieve Your Records + +You can use the SDK to retrieve all course records at once, or narrow your search down to retrieve records based on specific criteria. + +===== Retrieve All Course Records + +To retrieve all of your course records using the Java SDK: + +. In your `java` directory, create a new file called `ArtSchoolRetriever.java`. +. Paste the following code block into your `ArtSchoolRetriever.java` file: ++ +[source, java] +---- +include::devguide:example$java/ArtSchoolRetrieverAll.java[] +---- ++ +. In the `ArtSchoolRetriever.java` file, replace the `\<>`, `\<>`, and `\<>` placeholders with the connection string, username, and password that you noted when configuring the cluster connection. +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and rebuild your application. +. Run the following command to retrieve all course records: ++ +[source, sh] +---- +mvn exec:java -Dexec.mainClass="ArtSchoolRetriever" -Dexec.cleanupDaemonThreads=false +---- ++ +If the retrieval is successful, the course information outputs in the console log. ++ +image::record-retrieval-console-output.png[alt="Console showing successful course retrieval using the SDK"] + +===== Retrieve Course Records with Less than 200 Credits + +You can set parameters in your code to narrow your search down further. +To retrieve only courses with less than 200 `credit-points` using the Java SDK: + +. In your `java` directory, create a new file called `ArtSchoolRetrieverParameters.java`. +. Paste the following code block into your `ArtSchoolRetrieverParameters.java` file: ++ +[source, java] +---- +include::devguide:example$java/ArtSchoolRetriever.java[] +---- ++ +. In the `ArtSchoolRetrieverParameters.java` file, replace the `\<>`, `\<>`, and `\<>` placeholders with the connection string, username, and password that you noted when configuring the cluster connection. +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and rebuild your application. +. Run the following command to retrieve all course records: ++ +[source, sh] +---- +mvn exec:java -Dexec.mainClass="ArtSchoolRetrieverParameters" -Dexec.cleanupDaemonThreads=false +---- ++ +If the retrieval is successful, the course information with your parameters outputs in the console log. ++ +image::record-retrieval-parameters-console-output.png[alt="Console showing successful course retrieval using parameters using the SDK"] + +If you come across errors in your console, see the <<#roubleshooting,troubleshooting section>>. + + +== Add Course Enrollments + +After retrieving student and course records, you can add enrollment details to the student records using the SDK. + + +=== Add Enrollment Details + +To add enrollment details to a student record: + +. In your `java` directory, create a new file called `AddEnrollments.java`. +. Paste the following code block into your `AddEnrollments.java` file: ++ +[source, java] +---- +include::devguide:example$java/AddEnrollments.java[] +---- ++ +NOTE: Because this is a tutorial, you do not need to add an error check to make sure that your collection has returned an item. +In a live application, error checks must be made to prevent errors and keep the application running. ++ +. In the `AddEnrollments.java` file, replace the `\<>`, `\<>`, and `\<>` placeholders with the connection string, username, and password that you noted when configuring the cluster connection. +. Open a terminal window and navigate to your `student` directory. +. Run the command `mvn install` to pull in all the dependencies and rebuild your application. +. Run the following command to insert the student record into the collection: ++ +[source, sh] +---- +mvn exec:java -Dexec.mainClass="AddEnrollments" -Dexec.cleanupDaemonThreads=false +---- ++ +. From the Capella UI, go to your student cluster. +. Go to the `student-record-collection` and click the document ID to see the new information you just added to Hilary's student record. ++ +image::updated-student-record.png[alt="Updated student record with course enrollment" width="600" height="800"] + +If you come across errors in your console, see the <<#roubleshooting,troubleshooting section>>. + +=== Next Steps + +Now that you have finished following the Student Record System tutorial, +you can explore more of Capella Operational by checking out the rest of the xref:cloud:develop:intro.adoc[developer documentation], +or look at working with the xref:concept-docs:data-durability-acid-transactions.adoc[Data Service] +or xref:concept-docs:querying-your-data.adoc[{sqlpp} Queries] from the SDK. + + + +== Troubleshooting + +Below are some tutorial-specific tips for troubleshooting -- +you can find more detailed troubleshooting for connecting to Capella in our xref:howtos:troubleshooting-cloud-connections.adoc[Troubleshooting Cloud Connections] page. + + +=== Authentication Error + +If you get an authentication error when running Maven commands in your console, confirm that the username and password in your Java file matches the username and password you used when setting up the Capella Operational cluster in your browser. + +If they do not match, you can edit the Java file to add the correct username or password and try compiling and running the Maven command again. + +=== Unknown Host Exception + +If you get an `UnknownHostException` error in your console, go to your Java file and confirm that the connection string matches the one provided by the Capella Operational cluster. + +=== Other Build Errors + +For any other build errors in your console, run `mvn install` and try the original command again. + + + + diff --git a/modules/hello-world/partials/diagrams/couchbase-hierarchy.puml b/modules/hello-world/partials/diagrams/couchbase-hierarchy.puml new file mode 100644 index 00000000..8698dfd2 --- /dev/null +++ b/modules/hello-world/partials/diagrams/couchbase-hierarchy.puml @@ -0,0 +1,42 @@ +@startuml + +node "Couchbase cluster" as cluster + +database "Bucket" as bucket + +rectangle "Scope" as scope + +folder "Collection" as collection + + + +file "Document 1" as document1 +file "Document 2" as document2 +file "Document 3" as document3 + +cluster --> bucket +bucket --> scope +scope --> collection +collection --> document1 +collection --> document2 +collection --> document3 + +note right of bucket + + Maximum of 30 per cluster + +end note + +note left of scope + + Maximum of 1000 per cluster + +end note + +note right of collection + + Maximum of 1000 per cluster + +end note + +@enduml diff --git a/modules/hello-world/partials/diagrams/student-document-database-design.puml b/modules/hello-world/partials/diagrams/student-document-database-design.puml new file mode 100644 index 00000000..882546c3 --- /dev/null +++ b/modules/hello-world/partials/diagrams/student-document-database-design.puml @@ -0,0 +1,36 @@ +@startuml +left to right direction + + + database "student-bucket" { + + node "art-school-scope" { + + folder "student-record-collection" { + + file "Hilary's record" as hilary { + file "enrollment details" as hilary_enrollment + } + + file "Ashley's record" as ashley { + file "enrollment details" as ashley_enrollment + + } + + } + + folder "course-record-collection" { + + file "ART-HISTORY-000001" as art_history + file "GRAPHIC-DESIGN-000003" as graphic_design + file "FINE_ART-000002" as fine_art + } + + hilary_enrollment --> art_history + hilary_enrollment --> graphic_design + ashley_enrollment -->fine_art + } + + } + +@enduml diff --git a/modules/hello-world/partials/diagrams/student-record-erd.puml b/modules/hello-world/partials/diagrams/student-record-erd.puml new file mode 100644 index 00000000..137a44e9 --- /dev/null +++ b/modules/hello-world/partials/diagrams/student-record-erd.puml @@ -0,0 +1,31 @@ +@startuml +skinparam linetype ortho +entity student { + * student-id +-- + name + date-of-birth +} + + +entity course { + * course-id + course-name + faculty + credit-points +} + +entity enrollment { + + * student-id + * course-id +-- + * date-enrolled + date-completed +} + + +student --o{ enrollment +course --o{ enrollment + +@enduml