From abcdb15c2b1ea1cb7db9125bf361227d9e179a3e Mon Sep 17 00:00:00 2001 From: Andrew Feldman Date: Mon, 11 May 2020 04:04:55 -0700 Subject: [PATCH 1/8] Created DatabaseCRUDQuickstart.java --- .../sync/CollectionCRUDQuickstartSync.java | 4 + .../sync/DatabaseCRUDQuickstart.java | 137 +++++++ .../sync/DocumentCRUDQuickstartSync.java | 4 + .../queries/sync/QueriesQuickstartSync.java | 4 + .../sync/UserManagementQuickstartSync.java | 4 + .../workedappexample/SampleGroceryStore.java | 338 ------------------ 6 files changed, 153 insertions(+), 338 deletions(-) create mode 100644 src/main/java/com/azure/cosmos/examples/collectioncrud/sync/CollectionCRUDQuickstartSync.java create mode 100644 src/main/java/com/azure/cosmos/examples/databasecrud/sync/DatabaseCRUDQuickstart.java create mode 100644 src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstartSync.java create mode 100644 src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstartSync.java create mode 100644 src/main/java/com/azure/cosmos/examples/usermanagement/sync/UserManagementQuickstartSync.java delete mode 100644 src/main/java/com/azure/cosmos/examples/workedappexample/SampleGroceryStore.java diff --git a/src/main/java/com/azure/cosmos/examples/collectioncrud/sync/CollectionCRUDQuickstartSync.java b/src/main/java/com/azure/cosmos/examples/collectioncrud/sync/CollectionCRUDQuickstartSync.java new file mode 100644 index 0000000..cef46c4 --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/collectioncrud/sync/CollectionCRUDQuickstartSync.java @@ -0,0 +1,4 @@ +package com.azure.cosmos.examples.collectioncrud.sync; + +public class CollectionCRUDQuickstartSync { +} diff --git a/src/main/java/com/azure/cosmos/examples/databasecrud/sync/DatabaseCRUDQuickstart.java b/src/main/java/com/azure/cosmos/examples/databasecrud/sync/DatabaseCRUDQuickstart.java new file mode 100644 index 0000000..1a34cac --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/databasecrud/sync/DatabaseCRUDQuickstart.java @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.examples.databasecrud.sync; + +import com.azure.cosmos.ConsistencyLevel; +import com.azure.cosmos.CosmosClient; +import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosDatabase; +import com.azure.cosmos.CosmosPagedIterable; +import com.azure.cosmos.examples.changefeed.SampleChangeFeedProcessor; +import com.azure.cosmos.examples.common.AccountSettings; +import com.azure.cosmos.models.CosmosDatabaseProperties; +import com.azure.cosmos.models.CosmosDatabaseRequestOptions; +import com.azure.cosmos.models.CosmosDatabaseResponse; +import com.azure.cosmos.models.FeedOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DatabaseCRUDQuickstart { + + private CosmosClient client; + + private final String databaseName = "AzureSampleFamilyDB"; + + private CosmosDatabase database; + + protected static Logger logger = LoggerFactory.getLogger(SampleChangeFeedProcessor.class.getSimpleName()); + + public void close() { + client.close(); + } + + /** + * Sample to demonstrate the following database CRUD operations: + * -Create + * -Read by ID + * -Read all + * -Delete + */ + public static void main(String[] args) { + DatabaseCRUDQuickstart p = new DatabaseCRUDQuickstart(); + + try { + logger.info("Starting SYNC main"); + p.databaseCRUDDemo(); + logger.info("Demo complete, please hold while resources are released"); + } catch (Exception e) { + e.printStackTrace(); + logger.error(String.format("Cosmos getStarted failed with %s", e)); + } finally { + logger.info("Closing the client"); + p.shutdown(); + } + } + + private void databaseCRUDDemo() throws Exception { + + logger.info("Using Azure Cosmos DB endpoint: " + AccountSettings.HOST); + + // Create sync client + client = new CosmosClientBuilder() + .setEndpoint(AccountSettings.HOST) + .setKey(AccountSettings.MASTER_KEY) + .setConsistencyLevel(ConsistencyLevel.EVENTUAL) + .buildClient(); + + + createDatabaseIfNotExists(); + readDatabaseById(); + readAllDatabases(); + // deleteADatabase() is called at shutdown() + + } + + // Database Create + private void createDatabaseIfNotExists() throws Exception { + logger.info("Create database " + databaseName + " if not exists..."); + + // Create database if not exists + database = client.createDatabaseIfNotExists(databaseName).getDatabase(); + + logger.info("Done."); + } + + // Database read + private void readDatabaseById() throws Exception { + logger.info("Read database " + databaseName + " by ID."); + + // Read database by ID + database = client.getDatabase(databaseName); + + logger.info("Done."); + } + + // Database read all + private void readAllDatabases() throws Exception { + logger.info("Read all databases in the account."); + + // Read all databases in the account + CosmosPagedIterable databases = client.readAllDatabases(new FeedOptions()); + + // Print + String msg="Listing databases in account:\n"; + for(CosmosDatabaseProperties dbProps : databases) { + msg += String.format("-Database ID: %s\n",dbProps.getId()); + } + logger.info(msg + "\n"); + + logger.info("Done."); + } + + // Database delete + private void deleteADatabase() throws Exception { + logger.info("Last step: delete database " + databaseName + " by ID."); + + // Delete database + CosmosDatabaseResponse dbResp = client.getDatabase(databaseName).delete(new CosmosDatabaseRequestOptions()); + logger.info("Status code for database delete: {}",dbResp.getStatusCode()); + + logger.info("Done."); + } + + // Cleanup before close + private void shutdown() { + try { + //Clean shutdown + deleteADatabase(); + } catch (Exception err) { + logger.error("Deleting Cosmos DB resources failed, will still attempt to close the client. See stack trace below."); + err.printStackTrace(); + } + client.close(); + logger.info("Done with sample."); + } + +} diff --git a/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstartSync.java b/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstartSync.java new file mode 100644 index 0000000..59de052 --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstartSync.java @@ -0,0 +1,4 @@ +package com.azure.cosmos.examples.documentcrud.sync; + +public class DocumentCRUDQuickstartSync { +} diff --git a/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstartSync.java b/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstartSync.java new file mode 100644 index 0000000..fff294d --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstartSync.java @@ -0,0 +1,4 @@ +package com.azure.cosmos.examples.queries.sync; + +public class QueriesQuickstartSync { +} diff --git a/src/main/java/com/azure/cosmos/examples/usermanagement/sync/UserManagementQuickstartSync.java b/src/main/java/com/azure/cosmos/examples/usermanagement/sync/UserManagementQuickstartSync.java new file mode 100644 index 0000000..a9bb4fe --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/usermanagement/sync/UserManagementQuickstartSync.java @@ -0,0 +1,4 @@ +package com.azure.cosmos.examples.usermanagement.sync; + +public class UserManagementQuickstartSync { +} diff --git a/src/main/java/com/azure/cosmos/examples/workedappexample/SampleGroceryStore.java b/src/main/java/com/azure/cosmos/examples/workedappexample/SampleGroceryStore.java deleted file mode 100644 index 701c0fb..0000000 --- a/src/main/java/com/azure/cosmos/examples/workedappexample/SampleGroceryStore.java +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -package com.azure.cosmos.examples.workedappexample; - -import com.azure.cosmos.ChangeFeedProcessor; -import com.azure.cosmos.ConnectionPolicy; -import com.azure.cosmos.ConsistencyLevel; -import com.azure.cosmos.CosmosAsyncContainer; -import com.azure.cosmos.CosmosAsyncDatabase; -import com.azure.cosmos.CosmosClientBuilder; -import com.azure.cosmos.CosmosClientException; -import com.azure.cosmos.CosmosAsyncClient; -import com.azure.cosmos.CosmosPagedFlux; -import com.azure.cosmos.examples.common.AccountSettings; -import com.azure.cosmos.examples.common.Family; -import com.azure.cosmos.implementation.Utils; -import com.azure.cosmos.models.CosmosAsyncContainerResponse; -import com.azure.cosmos.models.CosmosContainerProperties; -import com.azure.cosmos.models.CosmosContainerRequestOptions; -import com.azure.cosmos.models.FeedOptions; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import org.apache.commons.lang3.RandomStringUtils; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.scheduler.Schedulers; - -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.time.Duration; -import java.util.Date; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -/** - * End-to-end application example code using Change Feed. - * - * This sample application inserts grocery store inventory data into an Azure Cosmos DB container; - * meanwhile, Change Feed runs in the background building a materialized view - * based on each document update. - * - * The materialized view facilitates efficient queries over item type. - * - */ -public class SampleGroceryStore { - - public static int WAIT_FOR_WORK = 60000; - public static final String DATABASE_NAME = "db_" + RandomStringUtils.randomAlphabetic(7); - public static final String COLLECTION_NAME = "coll_" + RandomStringUtils.randomAlphabetic(7); - private static final ObjectMapper OBJECT_MAPPER = Utils.getSimpleObjectMapper(); - protected static Logger logger = LoggerFactory.getLogger(SampleGroceryStore.class.getSimpleName()); - - - private static ChangeFeedProcessor changeFeedProcessorInstance; - private static boolean isWorkCompleted = false; - - private static CosmosAsyncContainer typeContainer; - - public static void main (String[]args) { - logger.info("BEGIN Sample"); - - try { - - System.out.println("Press enter to create the grocery store inventory system..."); - - System.out.println("-->CREATE DocumentClient"); - CosmosAsyncClient client = getCosmosClient(); - - System.out.println("-->CREATE Contoso Grocery Store database: " + DATABASE_NAME); - CosmosAsyncDatabase cosmosDatabase = createNewDatabase(client, DATABASE_NAME); - - System.out.println("-->CREATE container for store inventory: " + COLLECTION_NAME); - CosmosAsyncContainer feedContainer = createNewCollection(client, DATABASE_NAME, COLLECTION_NAME, "/id"); - - System.out.println("-->CREATE container for lease: " + COLLECTION_NAME + "-leases"); - CosmosAsyncContainer leaseContainer = createNewLeaseCollection(client, DATABASE_NAME, COLLECTION_NAME + "-leases"); - - System.out.println("-->CREATE container for materialized view partitioned by 'type': " + COLLECTION_NAME + "-leases"); - typeContainer = createNewCollection(client, DATABASE_NAME, COLLECTION_NAME + "-pktype", "/type"); - - System.out.println("Press enter to add items to the grocery store inventory system..."); - - changeFeedProcessorInstance = getChangeFeedProcessor("SampleHost_1", feedContainer, leaseContainer); - changeFeedProcessorInstance.start() - .subscribeOn(Schedulers.elastic()) - .doOnSuccess(aVoid -> { - //Insert 10 documents into the feed container - //createNewDocumentsJSON demonstrates how to insert a JSON object into a Cosmos DB container as an item - createNewDocumentsJSON(feedContainer, 10, Duration.ofSeconds(3)); - isWorkCompleted = true; - }) - .subscribe(); - - long remainingWork = WAIT_FOR_WORK; - while (!isWorkCompleted && remainingWork > 0) { - Thread.sleep(100); - remainingWork -= 100; - } - - if (isWorkCompleted) { - if (changeFeedProcessorInstance != null) { - changeFeedProcessorInstance.stop().subscribe(); - } - } else { - throw new RuntimeException("The change feed processor initialization and automatic create document feeding process did not complete in the expected time"); - } - - System.out.println("Press enter to query the materialized view..."); - - queryItems("SELECT * FROM c WHERE c.type IN ('milk','pens')", typeContainer); - - System.out.println("Press enter to clean up & exit the sample code..."); - - System.out.println("-->DELETE sample's database: " + DATABASE_NAME); - deleteDatabase(cosmosDatabase); - - Thread.sleep(500); - - } catch (Exception e) { - e.printStackTrace(); - } - - System.out.println("END Sample"); - } - - public static ChangeFeedProcessor getChangeFeedProcessor(String hostName, CosmosAsyncContainer feedContainer, CosmosAsyncContainer leaseContainer) { - return ChangeFeedProcessor.changeFeedProcessorBuilder() - .setHostName(hostName) - .setFeedContainer(feedContainer) - .setLeaseContainer(leaseContainer) - .setHandleChanges((List docs) -> { - for (JsonNode document : docs) { - //Duplicate each document update from the feed container into the materialized view container - updateInventoryTypeMaterializedView(document); - } - - }) - .build(); - } - - private static void updateInventoryTypeMaterializedView(JsonNode document) { - typeContainer.createItem(document).subscribe(); - } - - public static CosmosAsyncClient getCosmosClient() { - - return new CosmosClientBuilder() - .setEndpoint(AccountSettings.HOST) - .setKey(AccountSettings.MASTER_KEY) - .setConnectionPolicy(ConnectionPolicy.getDefaultPolicy()) - .setConsistencyLevel(ConsistencyLevel.EVENTUAL) - .buildAsyncClient(); - } - - public static CosmosAsyncDatabase createNewDatabase(CosmosAsyncClient client, String databaseName) { - return client.createDatabaseIfNotExists(databaseName).block().getDatabase(); - } - - public static void deleteDatabase(CosmosAsyncDatabase cosmosDatabase) { - cosmosDatabase.delete().block(); - } - - public static CosmosAsyncContainer createNewCollection(CosmosAsyncClient client, String databaseName, String collectionName, String partitionKey) { - CosmosAsyncDatabase databaseLink = client.getDatabase(databaseName); - CosmosAsyncContainer collectionLink = databaseLink.getContainer(collectionName); - CosmosAsyncContainerResponse containerResponse = null; - - try { - containerResponse = collectionLink.read().block(); - - if (containerResponse != null) { - throw new IllegalArgumentException(String.format("Collection %s already exists in database %s.", collectionName, databaseName)); - } - } catch (RuntimeException ex) { - if (ex instanceof CosmosClientException) { - CosmosClientException cosmosClientException = (CosmosClientException) ex; - - if (cosmosClientException.getStatusCode() != 404) { - throw ex; - } - } else { - throw ex; - } - } - - CosmosContainerProperties containerSettings = new CosmosContainerProperties(collectionName, partitionKey); - CosmosContainerRequestOptions requestOptions = new CosmosContainerRequestOptions(); - containerResponse = databaseLink.createContainer(containerSettings, 10000, requestOptions).block(); - - if (containerResponse == null) { - throw new RuntimeException(String.format("Failed to create collection %s in database %s.", collectionName, databaseName)); - } - - return containerResponse.getContainer(); - } - - public static CosmosAsyncContainer createNewLeaseCollection(CosmosAsyncClient client, String databaseName, String leaseCollectionName) { - CosmosAsyncDatabase databaseLink = client.getDatabase(databaseName); - CosmosAsyncContainer leaseCollectionLink = databaseLink.getContainer(leaseCollectionName); - CosmosAsyncContainerResponse leaseContainerResponse = null; - - try { - leaseContainerResponse = leaseCollectionLink.read().block(); - - if (leaseContainerResponse != null) { - leaseCollectionLink.delete().block(); - - try { - Thread.sleep(1000); - } catch (InterruptedException ex) { - ex.printStackTrace(); - } - } - } catch (RuntimeException ex) { - if (ex instanceof CosmosClientException) { - CosmosClientException cosmosClientException = (CosmosClientException) ex; - - if (cosmosClientException.getStatusCode() != 404) { - throw ex; - } - } else { - throw ex; - } - } - - CosmosContainerProperties containerSettings = new CosmosContainerProperties(leaseCollectionName, "/id"); - CosmosContainerRequestOptions requestOptions = new CosmosContainerRequestOptions(); - - leaseContainerResponse = databaseLink.createContainer(containerSettings, 400,requestOptions).block(); - - if (leaseContainerResponse == null) { - throw new RuntimeException(String.format("Failed to create collection %s in database %s.", leaseCollectionName, databaseName)); - } - - return leaseContainerResponse.getContainer(); - } - - public static void createNewDocumentsJSON(CosmosAsyncContainer containerClient, int count, Duration delay) { - System.out.println("Creating documents\n"); - String suffix = RandomStringUtils.randomAlphabetic(10); - for (int i = 0; i <= count; i++) { - - String jsonString = "{\"id\" : \"" + String.format("0%d-%s", i, suffix) + "\"" - + "," - + "\"brand\" : \"" + ((char)(65+i)) + "\"" - + "," - + "\"type\" : \"" + ((char)(69+i)) + "\"" - + "," - + "\"expiryDate\" : \"" + "2020-03-" + StringUtils.leftPad(String.valueOf(5+i), 2, "0") + "\"" - + "}"; - - ObjectMapper mapper = new ObjectMapper(); - JsonNode document = null; - - try { - document = mapper.readTree(jsonString); - } catch (Exception e) { - e.printStackTrace(); - } - - containerClient.createItem(document).subscribe(doc -> { - System.out.println(".\n"); - }); - - long remainingWork = delay.toMillis(); - try { - while (remainingWork > 0) { - Thread.sleep(100); - remainingWork -= 100; - } - } catch (InterruptedException iex) { - // exception caught - break; - } - } - } - - public static void queryItems(String query, CosmosAsyncContainer container) { - - FeedOptions queryOptions = new FeedOptions(); - queryOptions.setMaxItemCount(10); - // Set populate query metrics to get metrics around query executions - queryOptions.setPopulateQueryMetrics(true); - - CosmosPagedFlux pagedFluxResponse = container.queryItems( - query, queryOptions, JsonNode.class); - - final CountDownLatch completionLatch = new CountDownLatch(1); - - pagedFluxResponse.byPage().subscribe( - fluxResponse -> { - logger.info("Got a page of query result with " + - fluxResponse.getResults().size() + " items(s)" - + " and request charge of " + fluxResponse.getRequestCharge()); - - /* - fluxResponse.getResults() - - logger.info("Item Ids " + fluxResponse - .getResults() - .stream() - .map(JsonNode::get("id")) - .collect(Collectors.toList())); - - */ - }, - err -> { - if (err instanceof CosmosClientException) { - //Client-specific errors - CosmosClientException cerr = (CosmosClientException) err; - cerr.printStackTrace(); - logger.error(String.format("Read Item failed with %s\n", cerr)); - } else { - //General errors - err.printStackTrace(); - } - - completionLatch.countDown(); - }, - () -> { - completionLatch.countDown(); - } - ); - - try { - completionLatch.await(); - } catch (InterruptedException err) { - throw new AssertionError("Unexpected Interruption", err); - } - } - -} From d771500a5c40ad7fa52e45b8c518f1a85055c2d8 Mon Sep 17 00:00:00 2001 From: Andrew Feldman Date: Mon, 11 May 2020 04:25:36 -0700 Subject: [PATCH 2/8] Added container CRUD sample --- .../sync/CollectionCRUDQuickstartSync.java | 4 - .../sync/ContainerCRUDQuickstart.java | 180 ++++++++++++++++++ 2 files changed, 180 insertions(+), 4 deletions(-) delete mode 100644 src/main/java/com/azure/cosmos/examples/collectioncrud/sync/CollectionCRUDQuickstartSync.java create mode 100644 src/main/java/com/azure/cosmos/examples/containercrud/sync/ContainerCRUDQuickstart.java diff --git a/src/main/java/com/azure/cosmos/examples/collectioncrud/sync/CollectionCRUDQuickstartSync.java b/src/main/java/com/azure/cosmos/examples/collectioncrud/sync/CollectionCRUDQuickstartSync.java deleted file mode 100644 index cef46c4..0000000 --- a/src/main/java/com/azure/cosmos/examples/collectioncrud/sync/CollectionCRUDQuickstartSync.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.azure.cosmos.examples.collectioncrud.sync; - -public class CollectionCRUDQuickstartSync { -} diff --git a/src/main/java/com/azure/cosmos/examples/containercrud/sync/ContainerCRUDQuickstart.java b/src/main/java/com/azure/cosmos/examples/containercrud/sync/ContainerCRUDQuickstart.java new file mode 100644 index 0000000..0982956 --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/containercrud/sync/ContainerCRUDQuickstart.java @@ -0,0 +1,180 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.examples.containercrud.sync; + +import com.azure.cosmos.ConsistencyLevel; +import com.azure.cosmos.CosmosClient; +import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosContainer; +import com.azure.cosmos.CosmosDatabase; +import com.azure.cosmos.CosmosPagedIterable; +import com.azure.cosmos.examples.changefeed.SampleChangeFeedProcessor; +import com.azure.cosmos.examples.common.AccountSettings; +import com.azure.cosmos.models.CosmosContainerProperties; +import com.azure.cosmos.models.CosmosContainerRequestOptions; +import com.azure.cosmos.models.CosmosContainerResponse; +import com.azure.cosmos.models.CosmosDatabaseRequestOptions; +import com.azure.cosmos.models.CosmosDatabaseResponse; +import com.azure.cosmos.models.FeedOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ContainerCRUDQuickstart { + + private CosmosClient client; + + private final String databaseName = "AzureSampleFamilyDB"; + private final String containerName = "FamilyContainer"; + + private CosmosDatabase database; + private CosmosContainer container; + + protected static Logger logger = LoggerFactory.getLogger(SampleChangeFeedProcessor.class.getSimpleName()); + + public void close() { + client.close(); + } + + /** + * Sample to demonstrate the following container CRUD operations: + * -Create + * -Update throughput + * -Read by ID + * -Read all + * -Delete + */ + public static void main(String[] args) { + ContainerCRUDQuickstart p = new ContainerCRUDQuickstart(); + + try { + logger.info("Starting SYNC main"); + p.containerCRUDDemo(); + logger.info("Demo complete, please hold while resources are released"); + } catch (Exception e) { + e.printStackTrace(); + logger.error(String.format("Cosmos getStarted failed with %s", e)); + } finally { + logger.info("Closing the client"); + p.shutdown(); + } + } + + private void containerCRUDDemo() throws Exception { + + logger.info("Using Azure Cosmos DB endpoint: " + AccountSettings.HOST); + + // Create sync client + client = new CosmosClientBuilder() + .setEndpoint(AccountSettings.HOST) + .setKey(AccountSettings.MASTER_KEY) + .setConsistencyLevel(ConsistencyLevel.EVENTUAL) + .buildClient(); + + + createDatabaseIfNotExists(); + createContainerIfNotExists(); + + readContainerById(); + readAllContainers(); + // deleteAContainer() is called at shutdown() + + } + + // Database Create + private void createDatabaseIfNotExists() throws Exception { + logger.info("Create database " + databaseName + " if not exists..."); + + // Create database if not exists + database = client.createDatabaseIfNotExists(databaseName).getDatabase(); + + logger.info("Done."); + } + + private void createContainerIfNotExists() throws Exception { + logger.info("Create container " + containerName + " if not exists."); + + // Create container if not exists + CosmosContainerProperties containerProperties = + new CosmosContainerProperties(containerName, "/lastName"); + + // Create container with 400 RU/s + container = database.createContainerIfNotExists(containerProperties, 200).getContainer(); + + logger.info("Done."); + } + + // Update container throughput + private void updateContainerThroughput() throws Exception { + logger.info("Update throughput for container " + containerName + "."); + + // Specify new throughput value + container.replaceProvisionedThroughput(400); + + logger.info("Done."); + } + + // Container read + private void readContainerById() throws Exception { + logger.info("Read container " + containerName + " by ID."); + + // Read container by ID + container = database.getContainer(containerName); + + logger.info("Done."); + } + + // Container read all + private void readAllContainers() throws Exception { + logger.info("Read all containers in database " + databaseName + "."); + + // Read all containers in the account + CosmosPagedIterable containers = database.readAllContainers(new FeedOptions()); + + // Print + String msg="Listing containers in database:\n"; + for(CosmosContainerProperties containerProps : containers) { + msg += String.format("-Container ID: %s\n",containerProps.getId()); + } + logger.info(msg + "\n"); + + logger.info("Done."); + } + + // Container delete + private void deleteAContainer() throws Exception { + logger.info("Last step: delete container " + containerName + " by ID."); + + // Delete container + CosmosContainerResponse containerResp = database.getContainer(containerName).delete(new CosmosContainerRequestOptions()); + logger.info("Status code for container delete: {}",containerResp.getStatusCode()); + + logger.info("Done."); + } + + // Database delete + private void deleteADatabase() throws Exception { + logger.info("Last step: delete database " + databaseName + " by ID."); + + // Delete database + CosmosDatabaseResponse dbResp = client.getDatabase(databaseName).delete(new CosmosDatabaseRequestOptions()); + logger.info("Status code for database delete: {}",dbResp.getStatusCode()); + + logger.info("Done."); + } + + // Cleanup before close + private void shutdown() { + try { + //Clean shutdown + deleteAContainer(); + deleteADatabase(); + } catch (Exception err) { + logger.error("Deleting Cosmos DB resources failed, will still attempt to close the client. See stack trace below."); + err.printStackTrace(); + } + client.close(); + logger.info("Done with sample."); + } + +} From 5f2bdec717951061e94b90445e60b4d28537349f Mon Sep 17 00:00:00 2001 From: Andrew Feldman Date: Mon, 11 May 2020 07:22:41 -0700 Subject: [PATCH 3/8] Document CRUD samples --- .../azure/cosmos/examples/common/Address.java | 6 +- .../azure/cosmos/examples/common/Family.java | 14 +- .../sync/ContainerCRUDQuickstart.java | 5 +- .../sync/DocumentCRUDQuickstart.java | 341 ++++++++++++++++++ .../sync/DocumentCRUDQuickstartSync.java | 4 - 5 files changed, 354 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstart.java delete mode 100644 src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstartSync.java diff --git a/src/main/java/com/azure/cosmos/examples/common/Address.java b/src/main/java/com/azure/cosmos/examples/common/Address.java index ec7d5b3..9abbf3f 100644 --- a/src/main/java/com/azure/cosmos/examples/common/Address.java +++ b/src/main/java/com/azure/cosmos/examples/common/Address.java @@ -28,8 +28,8 @@ public void setCity(String city) { this.city = city; } - private String state; - private String county; - private String city; + private String state=""; + private String county=""; + private String city=""; } diff --git a/src/main/java/com/azure/cosmos/examples/common/Family.java b/src/main/java/com/azure/cosmos/examples/common/Family.java index 4e337b3..9a3c389 100644 --- a/src/main/java/com/azure/cosmos/examples/common/Family.java +++ b/src/main/java/com/azure/cosmos/examples/common/Family.java @@ -63,12 +63,12 @@ public void setRegistered(boolean isRegistered) { this.isRegistered = isRegistered; } - private String id; - private String lastName; - private String district; - private Parent[] parents; - private Child[] children; - private Address address; - private boolean isRegistered; + private String id=""; + private String lastName=""; + private String district=""; + private Parent[] parents={}; + private Child[] children={}; + private Address address=new Address(); + private boolean isRegistered=false; } diff --git a/src/main/java/com/azure/cosmos/examples/containercrud/sync/ContainerCRUDQuickstart.java b/src/main/java/com/azure/cosmos/examples/containercrud/sync/ContainerCRUDQuickstart.java index 0982956..771679e 100644 --- a/src/main/java/com/azure/cosmos/examples/containercrud/sync/ContainerCRUDQuickstart.java +++ b/src/main/java/com/azure/cosmos/examples/containercrud/sync/ContainerCRUDQuickstart.java @@ -91,6 +91,7 @@ private void createDatabaseIfNotExists() throws Exception { logger.info("Done."); } + // Container create private void createContainerIfNotExists() throws Exception { logger.info("Create container " + containerName + " if not exists."); @@ -98,7 +99,7 @@ private void createContainerIfNotExists() throws Exception { CosmosContainerProperties containerProperties = new CosmosContainerProperties(containerName, "/lastName"); - // Create container with 400 RU/s + // Create container with 200 RU/s container = database.createContainerIfNotExists(containerProperties, 200).getContainer(); logger.info("Done."); @@ -143,7 +144,7 @@ private void readAllContainers() throws Exception { // Container delete private void deleteAContainer() throws Exception { - logger.info("Last step: delete container " + containerName + " by ID."); + logger.info("Delete container " + containerName + " by ID."); // Delete container CosmosContainerResponse containerResp = database.getContainer(containerName).delete(new CosmosContainerRequestOptions()); diff --git a/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstart.java b/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstart.java new file mode 100644 index 0000000..8e0fade --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstart.java @@ -0,0 +1,341 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.examples.documentcrud.sync; + +import com.azure.cosmos.ConsistencyLevel; +import com.azure.cosmos.CosmosClient; +import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosClientException; +import com.azure.cosmos.CosmosContainer; +import com.azure.cosmos.CosmosDatabase; +import com.azure.cosmos.CosmosPagedIterable; +import com.azure.cosmos.examples.changefeed.SampleChangeFeedProcessor; +import com.azure.cosmos.examples.common.AccountSettings; +import com.azure.cosmos.examples.common.Family; +import com.azure.cosmos.implementation.http.HttpResponse; +import com.azure.cosmos.models.AccessCondition; +import com.azure.cosmos.models.AccessConditionType; +import com.azure.cosmos.models.CosmosContainerProperties; +import com.azure.cosmos.models.CosmosContainerRequestOptions; +import com.azure.cosmos.models.CosmosContainerResponse; +import com.azure.cosmos.models.CosmosDatabaseRequestOptions; +import com.azure.cosmos.models.CosmosDatabaseResponse; +import com.azure.cosmos.models.CosmosItemRequestOptions; +import com.azure.cosmos.models.CosmosItemResponse; +import com.azure.cosmos.models.FeedOptions; +import com.azure.cosmos.models.PartitionKey; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.UUID; + +public class DocumentCRUDQuickstart { + + private CosmosClient client; + + private final String databaseName = "AzureSampleFamilyDB"; + private final String containerName = "FamilyContainer"; + private final String documentId = UUID.randomUUID().toString(); + private final String documentLastName = "Witherspoon"; + + private CosmosDatabase database; + private CosmosContainer container; + + protected static Logger logger = LoggerFactory.getLogger(SampleChangeFeedProcessor.class.getSimpleName()); + + public void close() { + client.close(); + } + + /** + * Sample to demonstrate the following document CRUD operations: + * -Create + * -Read by ID + * -Read all + * -Query + * -Replace + * -Upsert + * -Replace with conditional ETag check + * -Read document only if document has changed + * -Delete + */ + public static void main(String[] args) { + DocumentCRUDQuickstart p = new DocumentCRUDQuickstart(); + + try { + logger.info("Starting SYNC main"); + p.documentCRUDDemo(); + logger.info("Demo complete, please hold while resources are released"); + } catch (Exception e) { + e.printStackTrace(); + logger.error(String.format("Cosmos getStarted failed with %s", e)); + } finally { + logger.info("Closing the client"); + p.shutdown(); + } + } + + private void documentCRUDDemo() throws Exception { + + logger.info("Using Azure Cosmos DB endpoint: " + AccountSettings.HOST); + + // Create sync client + client = new CosmosClientBuilder() + .setEndpoint(AccountSettings.HOST) + .setKey(AccountSettings.MASTER_KEY) + .setConsistencyLevel(ConsistencyLevel.EVENTUAL) + .buildClient(); + + + createDatabaseIfNotExists(); + createContainerIfNotExists(); + + createDocument(); + readDocumentById(); + readAllDocumentsInContainer(); + queryDocuments(); + replaceDocument(); + upsertDocument(); + replaceDocumentWithConditionalEtagCheck(); + readDocumentOnlyIfChanged(); + // deleteDocument() is called at shutdown() + + } + + // Database Create + private void createDatabaseIfNotExists() throws Exception { + logger.info("Create database " + databaseName + " if not exists..."); + + // Create database if not exists + database = client.createDatabaseIfNotExists(databaseName).getDatabase(); + + logger.info("Done."); + } + + // Container create + private void createContainerIfNotExists() throws Exception { + logger.info("Create container " + containerName + " if not exists."); + + // Create container if not exists + CosmosContainerProperties containerProperties = + new CosmosContainerProperties(containerName, "/lastName"); + + // Create container with 200 RU/s + container = database.createContainerIfNotExists(containerProperties, 200).getContainer(); + + logger.info("Done."); + } + + private void createDocument() throws Exception { + logger.info("Create document " + documentId); + + // Define a document as a POJO (internally this + // is converted to JSON via custom serialization) + Family family = new Family(); + family.setLastName(documentLastName); + family.setId(documentId); + + // Insert this item as a document + // Explicitly specifying the /pk value improves performance. + container.createItem(family,new PartitionKey(family.getLastName()),new CosmosItemRequestOptions()); + + logger.info("Done."); + } + + // Document read + private void readDocumentById() throws Exception { + logger.info("Read document " + documentId + " by ID."); + + // Read document by ID + Family family = container.readItem(documentId,new PartitionKey(documentLastName),Family.class).getResource(); + + // Check result + logger.info("Finished reading family " + family.getId() + " with partition key " + family.getLastName()); + + logger.info("Done."); + } + + // Container read all + private void readAllDocumentsInContainer() throws Exception { + logger.info("Read all documents in container " + containerName + "."); + + // Read all documents in the container + CosmosPagedIterable families = container.readAllItems(new FeedOptions(),Family.class); + + // Print + String msg="Listing documents in container:\n"; + for(Family family : families) { + msg += String.format("-Family (/id,partition key)): (%s,%s)\n",family.getId(),family.getLastName()); + } + logger.info(msg + "\n"); + + logger.info("Done."); + } + + private void queryDocuments() throws Exception { + logger.info("Query documents in the container " + containerName + "."); + + String sql = "SELECT * FROM c WHERE c.lastName = 'Witherspoon'"; + + CosmosPagedIterable filteredFamilies = container.queryItems(sql, new FeedOptions(), Family.class); + + // Print + if (filteredFamilies.iterator().hasNext()) { + Family family = filteredFamilies.iterator().next(); + logger.info("First query result: Family with (/id, partition key) = (%s,%s)",family.getId(),family.getLastName()); + } + + logger.info("Done."); + } + + private void replaceDocument() throws Exception { + logger.info("Replace document " + documentId); + + // Replace existing document with new modified document + Family family = new Family(); + family.setLastName(documentLastName); + family.setId(documentId); + family.setDistrict("Columbia"); // Document modification + + CosmosItemResponse famResp = + container.replaceItem(family, family.getId(), new PartitionKey(family.getLastName()), new CosmosItemRequestOptions()); + + logger.info("Request charge of replace operation: {} RU", famResp.getRequestCharge()); + + logger.info("Done."); + } + + private void upsertDocument() throws Exception { + logger.info("Replace document " + documentId); + + // Replace existing document with new modified document (contingent on modification). + Family family = new Family(); + family.setLastName(documentLastName); + family.setId(documentId); + family.setDistrict("Columbia"); // Document modification + + CosmosItemResponse famResp = + container.upsertItem(family, new CosmosItemRequestOptions()); + + logger.info("Done."); + } + + private void replaceDocumentWithConditionalEtagCheck() throws Exception { + logger.info("Replace document " + documentId + ", employing optimistic concurrency using ETag."); + + // Obtained current document ETag + CosmosItemResponse famResp = + container.readItem(documentId, new PartitionKey(documentLastName), Family.class); + String etag = famResp.getResponseHeaders().get("etag"); + + logger.info("Read document " + documentId + " to obtain current ETag: " + etag); + + // Modify document + Family family = famResp.getResource(); + family.setRegistered(!family.isRegistered()); + + // Persist the change back to the server, updating the ETag in the process + // This models a concurrent change made to the document + CosmosItemResponse updatedFamResp = + container.replaceItem(family,family.getId(),new PartitionKey(family.getLastName()),new CosmosItemRequestOptions()); + logger.info("'Concurrent' update to document " + documentId + " so ETag is now " + updatedFamResp.getResponseHeaders().get("etag")); + + // Now update the document and call replace with the AccessCondition requiring that ETag has not changed. + // This should fail because the "concurrent" document change updated the ETag. + try { + AccessCondition ac = new AccessCondition(); + ac.setType(AccessConditionType.IF_MATCH); + ac.setCondition(etag); + + CosmosItemRequestOptions requestOptions = new CosmosItemRequestOptions(); + requestOptions.setAccessCondition(ac); + + family.setDistrict("Seafood"); + + CosmosItemResponse failedFamResp = + container.replaceItem(family,family.getId(),new PartitionKey(family.getLastName()),requestOptions); + + } catch (CosmosClientException cce) { + logger.info("As expected, we have a pre-condition failure exception\n"); + } + + logger.info("Done."); + } + + private void readDocumentOnlyIfChanged() throws Exception { + logger.info("Read document " + documentId + " only if it has been changed, utilizing an ETag check."); + + // Read document + CosmosItemResponse famResp = + container.readItem(documentId, new PartitionKey(documentLastName), Family.class); + logger.info("Read doc with status code of {}", famResp.getStatusCode()); + + // Re-read but with conditional access requirement that ETag has changed. + // This should fail. + + String etag = famResp.getResponseHeaders().get("etag"); + AccessCondition ac = new AccessCondition(); + ac.setType(AccessConditionType.IF_NONE_MATCH); + ac.setCondition(etag); + CosmosItemRequestOptions requestOptions = new CosmosItemRequestOptions(); + requestOptions.setAccessCondition(ac); + + CosmosItemResponse failResp = + container.readItem(documentId, new PartitionKey(documentLastName), requestOptions, Family.class); + + logger.info("Re-read doc with status code of {} (we anticipate failure due to ETag not having changed.)", failResp.getStatusCode()); + + // Replace the doc with a modified version, which will update ETag + Family family = famResp.getResource(); + family.setRegistered(!family.isRegistered()); + CosmosItemResponse failedFamResp = + container.replaceItem(family,family.getId(),new PartitionKey(family.getLastName()),new CosmosItemRequestOptions()); + logger.info("Modified and replaced the doc (updates ETag.)"); + + // Re-read doc again, with conditional acccess requirements. + // This should succeed since ETag has been updated. + CosmosItemResponse succeedResp = + container.readItem(documentId, new PartitionKey(documentLastName), requestOptions, Family.class); + logger.info("Re-read doc with status code of {} (we anticipate success due to ETag modification.)", succeedResp.getStatusCode()); + + logger.info("Done."); + } + + // Document delete + private void deleteADocument() throws Exception { + logger.info("Delete document " + documentId + " by ID."); + + // Delete document + container.deleteItem(documentId, new PartitionKey(documentLastName), new CosmosItemRequestOptions()); + + logger.info("Done."); + } + + // Database delete + private void deleteADatabase() throws Exception { + logger.info("Last step: delete database " + databaseName + " by ID."); + + // Delete database + CosmosDatabaseResponse dbResp = client.getDatabase(databaseName).delete(new CosmosDatabaseRequestOptions()); + logger.info("Status code for database delete: {}",dbResp.getStatusCode()); + + logger.info("Done."); + } + + // Cleanup before close + private void shutdown() { + try { + //Clean shutdown + deleteADocument(); + deleteADatabase(); + } catch (Exception err) { + logger.error("Deleting Cosmos DB resources failed, will still attempt to close the client. See stack trace below."); + err.printStackTrace(); + } + client.close(); + logger.info("Done with sample."); + } + +} diff --git a/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstartSync.java b/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstartSync.java deleted file mode 100644 index 59de052..0000000 --- a/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstartSync.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.azure.cosmos.examples.documentcrud.sync; - -public class DocumentCRUDQuickstartSync { -} From 876552f80d4b854f7b549360195c97f0b12e64a9 Mon Sep 17 00:00:00 2001 From: Andrew Feldman Date: Mon, 11 May 2020 07:31:51 -0700 Subject: [PATCH 4/8] SOW on queries --- .../sync/DocumentCRUDQuickstart.java | 4 - .../queries/sync/QueriesQuickstart.java | 346 ++++++++++++++++++ .../queries/sync/QueriesQuickstartSync.java | 4 - 3 files changed, 346 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstart.java delete mode 100644 src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstartSync.java diff --git a/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstart.java b/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstart.java index 8e0fade..768956d 100644 --- a/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstart.java +++ b/src/main/java/com/azure/cosmos/examples/documentcrud/sync/DocumentCRUDQuickstart.java @@ -13,19 +13,15 @@ import com.azure.cosmos.examples.changefeed.SampleChangeFeedProcessor; import com.azure.cosmos.examples.common.AccountSettings; import com.azure.cosmos.examples.common.Family; -import com.azure.cosmos.implementation.http.HttpResponse; import com.azure.cosmos.models.AccessCondition; import com.azure.cosmos.models.AccessConditionType; import com.azure.cosmos.models.CosmosContainerProperties; -import com.azure.cosmos.models.CosmosContainerRequestOptions; -import com.azure.cosmos.models.CosmosContainerResponse; import com.azure.cosmos.models.CosmosDatabaseRequestOptions; import com.azure.cosmos.models.CosmosDatabaseResponse; import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosItemResponse; import com.azure.cosmos.models.FeedOptions; import com.azure.cosmos.models.PartitionKey; -import io.netty.handler.codec.http.HttpResponseStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstart.java b/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstart.java new file mode 100644 index 0000000..ea637a3 --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstart.java @@ -0,0 +1,346 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.examples.queries.sync; + +import com.azure.cosmos.ConsistencyLevel; +import com.azure.cosmos.CosmosClient; +import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosClientException; +import com.azure.cosmos.CosmosContainer; +import com.azure.cosmos.CosmosDatabase; +import com.azure.cosmos.CosmosPagedIterable; +import com.azure.cosmos.examples.changefeed.SampleChangeFeedProcessor; +import com.azure.cosmos.examples.common.AccountSettings; +import com.azure.cosmos.examples.common.Family; +import com.azure.cosmos.implementation.http.HttpResponse; +import com.azure.cosmos.models.AccessCondition; +import com.azure.cosmos.models.AccessConditionType; +import com.azure.cosmos.models.CosmosContainerProperties; +import com.azure.cosmos.models.CosmosContainerRequestOptions; +import com.azure.cosmos.models.CosmosContainerResponse; +import com.azure.cosmos.models.CosmosDatabaseRequestOptions; +import com.azure.cosmos.models.CosmosDatabaseResponse; +import com.azure.cosmos.models.CosmosItemRequestOptions; +import com.azure.cosmos.models.CosmosItemResponse; +import com.azure.cosmos.models.FeedOptions; +import com.azure.cosmos.models.PartitionKey; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.UUID; + +public class QueriesQuickstart { + + private CosmosClient client; + + private final String databaseName = "AzureSampleFamilyDB"; + private final String containerName = "FamilyContainer"; + private final String documentId = UUID.randomUUID().toString(); + private final String documentLastName = "Witherspoon"; + + private CosmosDatabase database; + private CosmosContainer container; + + protected static Logger logger = LoggerFactory.getLogger(SampleChangeFeedProcessor.class.getSimpleName()); + + public void close() { + client.close(); + } + + /** + * Sample to demonstrate Azure Cosmos DB queries via Java SQL API, including queries for: + * -All documents + * -Equality using == + * -Inequality using != and NOT + * -Using range operators like >, <, >=, <= + * -Using range operators against Strings + * -With ORDER BY + * -With aggregate functions + * -With subdocuments + * -With intra-document joins + * -With String, math and array operators + * -With parameterized SQL using SqlQuerySpec + * -With explicit paging + * -Query partitioned collections in parallel + * -With ORDER BY for partitioned collections + */ + public static void main(String[] args) { + QueriesQuickstart p = new QueriesQuickstart(); + + try { + logger.info("Starting SYNC main"); + p.queriesDemo(); + logger.info("Demo complete, please hold while resources are released"); + } catch (Exception e) { + e.printStackTrace(); + logger.error(String.format("Cosmos getStarted failed with %s", e)); + } finally { + logger.info("Closing the client"); + p.shutdown(); + } + } + + private void queriesDemo() throws Exception { + + logger.info("Using Azure Cosmos DB endpoint: " + AccountSettings.HOST); + + // Create sync client + client = new CosmosClientBuilder() + .setEndpoint(AccountSettings.HOST) + .setKey(AccountSettings.MASTER_KEY) + .setConsistencyLevel(ConsistencyLevel.EVENTUAL) + .buildClient(); + + + createDatabaseIfNotExists(); + createContainerIfNotExists(); + + createDocument(); + readDocumentById(); + readAllDocumentsInContainer(); + queryDocuments(); + replaceDocument(); + upsertDocument(); + replaceDocumentWithConditionalEtagCheck(); + readDocumentOnlyIfChanged(); + // deleteDocument() is called at shutdown() + + } + + // Database Create + private void createDatabaseIfNotExists() throws Exception { + logger.info("Create database " + databaseName + " if not exists..."); + + // Create database if not exists + database = client.createDatabaseIfNotExists(databaseName).getDatabase(); + + logger.info("Done."); + } + + // Container create + private void createContainerIfNotExists() throws Exception { + logger.info("Create container " + containerName + " if not exists."); + + // Create container if not exists + CosmosContainerProperties containerProperties = + new CosmosContainerProperties(containerName, "/lastName"); + + // Create container with 200 RU/s + container = database.createContainerIfNotExists(containerProperties, 200).getContainer(); + + logger.info("Done."); + } + + private void createDocument() throws Exception { + logger.info("Create document " + documentId); + + // Define a document as a POJO (internally this + // is converted to JSON via custom serialization) + Family family = new Family(); + family.setLastName(documentLastName); + family.setId(documentId); + + // Insert this item as a document + // Explicitly specifying the /pk value improves performance. + container.createItem(family,new PartitionKey(family.getLastName()),new CosmosItemRequestOptions()); + + logger.info("Done."); + } + + // Document read + private void readDocumentById() throws Exception { + logger.info("Read document " + documentId + " by ID."); + + // Read document by ID + Family family = container.readItem(documentId,new PartitionKey(documentLastName),Family.class).getResource(); + + // Check result + logger.info("Finished reading family " + family.getId() + " with partition key " + family.getLastName()); + + logger.info("Done."); + } + + // Container read all + private void readAllDocumentsInContainer() throws Exception { + logger.info("Read all documents in container " + containerName + "."); + + // Read all documents in the container + CosmosPagedIterable families = container.readAllItems(new FeedOptions(),Family.class); + + // Print + String msg="Listing documents in container:\n"; + for(Family family : families) { + msg += String.format("-Family (/id,partition key)): (%s,%s)\n",family.getId(),family.getLastName()); + } + logger.info(msg + "\n"); + + logger.info("Done."); + } + + private void queryDocuments() throws Exception { + logger.info("Query documents in the container " + containerName + "."); + + String sql = "SELECT * FROM c WHERE c.lastName = 'Witherspoon'"; + + CosmosPagedIterable filteredFamilies = container.queryItems(sql, new FeedOptions(), Family.class); + + // Print + if (filteredFamilies.iterator().hasNext()) { + Family family = filteredFamilies.iterator().next(); + logger.info("First query result: Family with (/id, partition key) = (%s,%s)",family.getId(),family.getLastName()); + } + + logger.info("Done."); + } + + private void replaceDocument() throws Exception { + logger.info("Replace document " + documentId); + + // Replace existing document with new modified document + Family family = new Family(); + family.setLastName(documentLastName); + family.setId(documentId); + family.setDistrict("Columbia"); // Document modification + + CosmosItemResponse famResp = + container.replaceItem(family, family.getId(), new PartitionKey(family.getLastName()), new CosmosItemRequestOptions()); + + logger.info("Request charge of replace operation: {} RU", famResp.getRequestCharge()); + + logger.info("Done."); + } + + private void upsertDocument() throws Exception { + logger.info("Replace document " + documentId); + + // Replace existing document with new modified document (contingent on modification). + Family family = new Family(); + family.setLastName(documentLastName); + family.setId(documentId); + family.setDistrict("Columbia"); // Document modification + + CosmosItemResponse famResp = + container.upsertItem(family, new CosmosItemRequestOptions()); + + logger.info("Done."); + } + + private void replaceDocumentWithConditionalEtagCheck() throws Exception { + logger.info("Replace document " + documentId + ", employing optimistic concurrency using ETag."); + + // Obtained current document ETag + CosmosItemResponse famResp = + container.readItem(documentId, new PartitionKey(documentLastName), Family.class); + String etag = famResp.getResponseHeaders().get("etag"); + + logger.info("Read document " + documentId + " to obtain current ETag: " + etag); + + // Modify document + Family family = famResp.getResource(); + family.setRegistered(!family.isRegistered()); + + // Persist the change back to the server, updating the ETag in the process + // This models a concurrent change made to the document + CosmosItemResponse updatedFamResp = + container.replaceItem(family,family.getId(),new PartitionKey(family.getLastName()),new CosmosItemRequestOptions()); + logger.info("'Concurrent' update to document " + documentId + " so ETag is now " + updatedFamResp.getResponseHeaders().get("etag")); + + // Now update the document and call replace with the AccessCondition requiring that ETag has not changed. + // This should fail because the "concurrent" document change updated the ETag. + try { + AccessCondition ac = new AccessCondition(); + ac.setType(AccessConditionType.IF_MATCH); + ac.setCondition(etag); + + CosmosItemRequestOptions requestOptions = new CosmosItemRequestOptions(); + requestOptions.setAccessCondition(ac); + + family.setDistrict("Seafood"); + + CosmosItemResponse failedFamResp = + container.replaceItem(family,family.getId(),new PartitionKey(family.getLastName()),requestOptions); + + } catch (CosmosClientException cce) { + logger.info("As expected, we have a pre-condition failure exception\n"); + } + + logger.info("Done."); + } + + private void readDocumentOnlyIfChanged() throws Exception { + logger.info("Read document " + documentId + " only if it has been changed, utilizing an ETag check."); + + // Read document + CosmosItemResponse famResp = + container.readItem(documentId, new PartitionKey(documentLastName), Family.class); + logger.info("Read doc with status code of {}", famResp.getStatusCode()); + + // Re-read but with conditional access requirement that ETag has changed. + // This should fail. + + String etag = famResp.getResponseHeaders().get("etag"); + AccessCondition ac = new AccessCondition(); + ac.setType(AccessConditionType.IF_NONE_MATCH); + ac.setCondition(etag); + CosmosItemRequestOptions requestOptions = new CosmosItemRequestOptions(); + requestOptions.setAccessCondition(ac); + + CosmosItemResponse failResp = + container.readItem(documentId, new PartitionKey(documentLastName), requestOptions, Family.class); + + logger.info("Re-read doc with status code of {} (we anticipate failure due to ETag not having changed.)", failResp.getStatusCode()); + + // Replace the doc with a modified version, which will update ETag + Family family = famResp.getResource(); + family.setRegistered(!family.isRegistered()); + CosmosItemResponse failedFamResp = + container.replaceItem(family,family.getId(),new PartitionKey(family.getLastName()),new CosmosItemRequestOptions()); + logger.info("Modified and replaced the doc (updates ETag.)"); + + // Re-read doc again, with conditional acccess requirements. + // This should succeed since ETag has been updated. + CosmosItemResponse succeedResp = + container.readItem(documentId, new PartitionKey(documentLastName), requestOptions, Family.class); + logger.info("Re-read doc with status code of {} (we anticipate success due to ETag modification.)", succeedResp.getStatusCode()); + + logger.info("Done."); + } + + // Document delete + private void deleteADocument() throws Exception { + logger.info("Delete document " + documentId + " by ID."); + + // Delete document + container.deleteItem(documentId, new PartitionKey(documentLastName), new CosmosItemRequestOptions()); + + logger.info("Done."); + } + + // Database delete + private void deleteADatabase() throws Exception { + logger.info("Last step: delete database " + databaseName + " by ID."); + + // Delete database + CosmosDatabaseResponse dbResp = client.getDatabase(databaseName).delete(new CosmosDatabaseRequestOptions()); + logger.info("Status code for database delete: {}",dbResp.getStatusCode()); + + logger.info("Done."); + } + + // Cleanup before close + private void shutdown() { + try { + //Clean shutdown + deleteADocument(); + deleteADatabase(); + } catch (Exception err) { + logger.error("Deleting Cosmos DB resources failed, will still attempt to close the client. See stack trace below."); + err.printStackTrace(); + } + client.close(); + logger.info("Done with sample."); + } + +} diff --git a/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstartSync.java b/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstartSync.java deleted file mode 100644 index fff294d..0000000 --- a/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstartSync.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.azure.cosmos.examples.queries.sync; - -public class QueriesQuickstartSync { -} From e3ac8c25c573a761cb867ee62ef19078a494914f Mon Sep 17 00:00:00 2001 From: Andrew Feldman Date: Fri, 15 May 2020 04:55:48 -0700 Subject: [PATCH 5/8] Query samples --- .../queries/sync/QueriesQuickstart.java | 336 ++++++++++++------ 1 file changed, 218 insertions(+), 118 deletions(-) diff --git a/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstart.java b/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstart.java index ea637a3..15cf790 100644 --- a/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstart.java +++ b/src/main/java/com/azure/cosmos/examples/queries/sync/QueriesQuickstart.java @@ -24,11 +24,17 @@ import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosItemResponse; import com.azure.cosmos.models.FeedOptions; +import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.PartitionKey; +import com.azure.cosmos.models.SqlParameter; +import com.azure.cosmos.models.SqlParameterList; +import com.azure.cosmos.models.SqlQuerySpec; +import com.fasterxml.jackson.databind.JsonNode; import io.netty.handler.codec.http.HttpResponseStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Iterator; import java.util.UUID; public class QueriesQuickstart { @@ -98,17 +104,53 @@ private void queriesDemo() throws Exception { createContainerIfNotExists(); createDocument(); - readDocumentById(); - readAllDocumentsInContainer(); - queryDocuments(); - replaceDocument(); - upsertDocument(); - replaceDocumentWithConditionalEtagCheck(); - readDocumentOnlyIfChanged(); + + queryAllDocuments(); + queryWithPagingAndContinuationTokenAndPrintQueryCharge(new FeedOptions()); + queryEquality(); + queryInequality(); + queryRange(); + queryRangeAgainstStrings(); + queryOrderBy(); + queryWithAggregateFunctions(); + querySubdocuments(); + queryIntraDocumentJoin(); + queryStringMathAndArrayOperators(); + queryWithQuerySpec(); + parallelQueryWithPagingAndContinuationTokenAndPrintQueryCharge(); + // deleteDocument() is called at shutdown() } + private void executeQueryPrintSingleResult(String sql) { + logger.info("Execute query {}",sql); + + CosmosPagedIterable filteredFamilies = container.queryItems(sql, new FeedOptions(), Family.class); + + // Print + if (filteredFamilies.iterator().hasNext()) { + Family family = filteredFamilies.iterator().next(); + logger.info("First query result: Family with (/id, partition key) = (%s,%s)",family.getId(),family.getLastName()); + } + + logger.info("Done."); + } + + private void executeQueryWithQuerySpecPrintSingleResult(SqlQuerySpec querySpec) { + logger.info("Execute query {}",querySpec.getQueryText()); + + CosmosPagedIterable filteredFamilies = container.queryItems(querySpec, new FeedOptions(), Family.class); + + // Print + if (filteredFamilies.iterator().hasNext()) { + Family family = filteredFamilies.iterator().next(); + logger.info("First query result: Family with (/id, partition key) = (%s,%s)",family.getId(),family.getLastName()); + } + + logger.info("Done."); + } + // Database Create private void createDatabaseIfNotExists() throws Exception { logger.info("Create database " + databaseName + " if not exists..."); @@ -149,163 +191,221 @@ private void createDocument() throws Exception { logger.info("Done."); } - // Document read - private void readDocumentById() throws Exception { - logger.info("Read document " + documentId + " by ID."); + private void queryAllDocuments() throws Exception { + logger.info("Query all documents."); - // Read document by ID - Family family = container.readItem(documentId,new PartitionKey(documentLastName),Family.class).getResource(); + executeQueryPrintSingleResult("SELECT * FROM c"); + } - // Check result - logger.info("Finished reading family " + family.getId() + " with partition key " + family.getLastName()); + private void queryWithPagingAndContinuationTokenAndPrintQueryCharge(FeedOptions options) throws Exception { + logger.info("Query with paging and continuation token; print the total RU charge of the query"); - logger.info("Done."); - } + String query = "SELECT * FROM Families"; - // Container read all - private void readAllDocumentsInContainer() throws Exception { - logger.info("Read all documents in container " + containerName + "."); + int pageSize = 100; //No of docs per page + int currentPageNumber = 1; + int documentNumber = 0; + String continuationToken = null; - // Read all documents in the container - CosmosPagedIterable families = container.readAllItems(new FeedOptions(),Family.class); + double requestCharge = 0.0; - // Print - String msg="Listing documents in container:\n"; - for(Family family : families) { - msg += String.format("-Family (/id,partition key)): (%s,%s)\n",family.getId(),family.getLastName()); - } - logger.info(msg + "\n"); + // First iteration (continuationToken == null): Receive a batch of query response pages + // Subsequent iterations (continuationToken != null): Receive subsequent batch of query response pages, with continuationToken indicating where the previous iteration left off + do { + logger.info("Receiving a set of query response pages."); + logger.info("Continuation Token: " + continuationToken + "\n"); - logger.info("Done."); + FeedOptions queryOptions = new FeedOptions(); + + // note that setMaxItemCount sets the number of items to return in a single page result + queryOptions.setMaxItemCount(pageSize); + queryOptions.setRequestContinuation(continuationToken); + + Iterable> feedResponseIterator = + container.queryItems(query, queryOptions, Family.class).iterableByPage(); + + for (FeedResponse page : feedResponseIterator) { + logger.info(String.format("Current page number: %d", currentPageNumber)); + // Access all of the documents in this result page + for (Family docProps : page.getResults()) { + documentNumber++; + } + + // Accumulate the request charge of this page + requestCharge += page.getRequestCharge(); + + // Page count so far + logger.info(String.format("Total documents received so far: %d", documentNumber)); + + // Request charge so far + logger.info(String.format("Total request charge so far: %f\n", requestCharge)); + + // Along with page results, get a continuation token + // which enables the client to "pick up where it left off" + // in accessing query response pages. + continuationToken = page.getContinuationToken(); + + currentPageNumber++; + } + + } while (continuationToken != null); + + logger.info(String.format("Total request charge: %f\n", requestCharge)); } - private void queryDocuments() throws Exception { - logger.info("Query documents in the container " + containerName + "."); + private void parallelQueryWithPagingAndContinuationTokenAndPrintQueryCharge() throws Exception { + logger.info("Parallel implementation of:"); - String sql = "SELECT * FROM c WHERE c.lastName = 'Witherspoon'"; + FeedOptions options = new FeedOptions(); - CosmosPagedIterable filteredFamilies = container.queryItems(sql, new FeedOptions(), Family.class); + // 0 maximum parallel tasks, effectively serial execution + options.setMaxDegreeOfParallelism(0); + options.setMaxBufferedItemCount(100); + queryWithPagingAndContinuationTokenAndPrintQueryCharge(options); - // Print - if (filteredFamilies.iterator().hasNext()) { - Family family = filteredFamilies.iterator().next(); - logger.info("First query result: Family with (/id, partition key) = (%s,%s)",family.getId(),family.getLastName()); - } + // 1 maximum parallel tasks, 1 dedicated asynchronous task to continuously make REST calls + options.setMaxDegreeOfParallelism(1); + options.setMaxBufferedItemCount(100); + queryWithPagingAndContinuationTokenAndPrintQueryCharge(options); - logger.info("Done."); + // 10 maximum parallel tasks, a maximum of 10 dedicated asynchronous tasks to continuously make REST calls + options.setMaxDegreeOfParallelism(10); + options.setMaxBufferedItemCount(100); + queryWithPagingAndContinuationTokenAndPrintQueryCharge(options); + + logger.info("Done with parallel queries."); } - private void replaceDocument() throws Exception { - logger.info("Replace document " + documentId); + private void queryEquality() throws Exception { + logger.info("Query for equality using =="); - // Replace existing document with new modified document - Family family = new Family(); - family.setLastName(documentLastName); - family.setId(documentId); - family.setDistrict("Columbia"); // Document modification + executeQueryPrintSingleResult("SELECT * FROM c WHERE c.id == '" + documentId + "'"); + } - CosmosItemResponse famResp = - container.replaceItem(family, family.getId(), new PartitionKey(family.getLastName()), new CosmosItemRequestOptions()); + private void queryInequality() throws Exception { + logger.info("Query for inequality"); - logger.info("Request charge of replace operation: {} RU", famResp.getRequestCharge()); + executeQueryPrintSingleResult("SELECT * FROM c WHERE c.id != '" + documentId + "'"); + executeQueryPrintSingleResult("SELECT * FROM c WHERE c.id <> '" + documentId + "'"); - logger.info("Done."); + // Combine equality and inequality + executeQueryPrintSingleResult("SELECT * FROM c WHERE c.lastName == '" + documentLastName + "' && c.id != '" + documentId + "'"); } - private void upsertDocument() throws Exception { - logger.info("Replace document " + documentId); + private void queryRange() throws Exception { + logger.info("Numerical range query"); - // Replace existing document with new modified document (contingent on modification). - Family family = new Family(); - family.setLastName(documentLastName); - family.setId(documentId); - family.setDistrict("Columbia"); // Document modification + // Numerical range query + executeQueryPrintSingleResult("SELECT * FROM Families f WHERE f.Children[0].Grade > 5"); + } - CosmosItemResponse famResp = - container.upsertItem(family, new CosmosItemRequestOptions()); + private void queryRangeAgainstStrings() throws Exception { + logger.info("String range query"); - logger.info("Done."); + // String range query + executeQueryPrintSingleResult("SELECT * FROM Families f WHERE f.Address.State > 'NY'"); } - private void replaceDocumentWithConditionalEtagCheck() throws Exception { - logger.info("Replace document " + documentId + ", employing optimistic concurrency using ETag."); + private void queryOrderBy() throws Exception { + logger.info("ORDER BY queries"); - // Obtained current document ETag - CosmosItemResponse famResp = - container.readItem(documentId, new PartitionKey(documentLastName), Family.class); - String etag = famResp.getResponseHeaders().get("etag"); + // Numerical ORDER BY + executeQueryPrintSingleResult("SELECT * FROM Families f WHERE f.LastName = 'Andersen' ORDER BY f.Children[0].Grade"); + } - logger.info("Read document " + documentId + " to obtain current ETag: " + etag); + private void queryDistinct() throws Exception { + logger.info("DISTINCT queries"); - // Modify document - Family family = famResp.getResource(); - family.setRegistered(!family.isRegistered()); + // DISTINCT query + executeQueryPrintSingleResult("SELECT DISTINCT c.lastName from c"); + } - // Persist the change back to the server, updating the ETag in the process - // This models a concurrent change made to the document - CosmosItemResponse updatedFamResp = - container.replaceItem(family,family.getId(),new PartitionKey(family.getLastName()),new CosmosItemRequestOptions()); - logger.info("'Concurrent' update to document " + documentId + " so ETag is now " + updatedFamResp.getResponseHeaders().get("etag")); + private void queryWithAggregateFunctions() throws Exception { + logger.info("Aggregate function queries"); - // Now update the document and call replace with the AccessCondition requiring that ETag has not changed. - // This should fail because the "concurrent" document change updated the ETag. - try { - AccessCondition ac = new AccessCondition(); - ac.setType(AccessConditionType.IF_MATCH); - ac.setCondition(etag); + // Basic query with aggregate functions + executeQueryPrintSingleResult("SELECT VALUE COUNT(f) FROM Families f WHERE f.LastName = 'Andersen'"); - CosmosItemRequestOptions requestOptions = new CosmosItemRequestOptions(); - requestOptions.setAccessCondition(ac); + // Query with aggregate functions within documents + executeQueryPrintSingleResult("SELECT VALUE COUNT(child) FROM child IN f.Children"); + } - family.setDistrict("Seafood"); + private void querySubdocuments() throws Exception { + // Cosmos DB supports the selection of sub-documents on the server, there + // is no need to send down the full family record if all you want to display + // is a single child - CosmosItemResponse failedFamResp = - container.replaceItem(family,family.getId(),new PartitionKey(family.getLastName()),requestOptions); + logger.info("Subdocument query"); - } catch (CosmosClientException cce) { - logger.info("As expected, we have a pre-condition failure exception\n"); - } + executeQueryPrintSingleResult("SELECT VALUE c FROM c IN f.Children"); + } - logger.info("Done."); + private void queryIntraDocumentJoin() throws Exception { + // Cosmos DB supports the notion of an Intra-document Join, or a self-join + // which will effectively flatten the hierarchy of a document, just like doing + // a self JOIN on a SQL table + + logger.info("Intra-document joins"); + + // Single join + executeQueryPrintSingleResult("SELECT f.id FROM Families f JOIN c IN f.Children"); + + // Two joins + executeQueryPrintSingleResult("SELECT f.id as family, c.FirstName AS child, p.GivenName AS pet " + + "FROM Families f " + + "JOIN c IN f.Children " + + "join p IN c.Pets"); + + // Two joins and a filter + executeQueryPrintSingleResult("SELECT f.id as family, c.FirstName AS child, p.GivenName AS pet " + + "FROM Families f " + + "JOIN c IN f.Children " + + "join p IN c.Pets " + + "WHERE p.GivenName = 'Fluffy'"); } - private void readDocumentOnlyIfChanged() throws Exception { - logger.info("Read document " + documentId + " only if it has been changed, utilizing an ETag check."); + private void queryStringMathAndArrayOperators() throws Exception { + logger.info("Queries with string, math and array operators"); - // Read document - CosmosItemResponse famResp = - container.readItem(documentId, new PartitionKey(documentLastName), Family.class); - logger.info("Read doc with status code of {}", famResp.getStatusCode()); + // String STARTSWITH operator + executeQueryPrintSingleResult("SELECT * FROM family WHERE STARTSWITH(family.LastName, 'An')"); - // Re-read but with conditional access requirement that ETag has changed. - // This should fail. + // Round down numbers with FLOOR + executeQueryPrintSingleResult("SELECT VALUE FLOOR(family.Children[0].Grade) FROM family"); - String etag = famResp.getResponseHeaders().get("etag"); - AccessCondition ac = new AccessCondition(); - ac.setType(AccessConditionType.IF_NONE_MATCH); - ac.setCondition(etag); - CosmosItemRequestOptions requestOptions = new CosmosItemRequestOptions(); - requestOptions.setAccessCondition(ac); + // Get number of children using array length + executeQueryPrintSingleResult("SELECT VALUE ARRAY_LENGTH(family.Children) FROM family"); + } - CosmosItemResponse failResp = - container.readItem(documentId, new PartitionKey(documentLastName), requestOptions, Family.class); + private void queryWithQuerySpec() throws Exception { + logger.info("Query with SqlQuerySpec"); - logger.info("Re-read doc with status code of {} (we anticipate failure due to ETag not having changed.)", failResp.getStatusCode()); + FeedOptions options = new FeedOptions(); + options.setPartitionKey(new PartitionKey("Witherspoon")); - // Replace the doc with a modified version, which will update ETag - Family family = famResp.getResource(); - family.setRegistered(!family.isRegistered()); - CosmosItemResponse failedFamResp = - container.replaceItem(family,family.getId(),new PartitionKey(family.getLastName()),new CosmosItemRequestOptions()); - logger.info("Modified and replaced the doc (updates ETag.)"); + // Simple query with a single property equality comparison + // in SQL with SQL parameterization instead of inlining the + // parameter values in the query string - // Re-read doc again, with conditional acccess requirements. - // This should succeed since ETag has been updated. - CosmosItemResponse succeedResp = - container.readItem(documentId, new PartitionKey(documentLastName), requestOptions, Family.class); - logger.info("Re-read doc with status code of {} (we anticipate success due to ETag modification.)", succeedResp.getStatusCode()); + SqlParameterList paramList = new SqlParameterList(); + paramList.add(new SqlParameter("@id", "AndersenFamily")); + SqlQuerySpec querySpec = new SqlQuerySpec( + "SELECT * FROM Families f WHERE (f.id = @id)", + paramList); - logger.info("Done."); + executeQueryWithQuerySpecPrintSingleResult(querySpec); + + // Query using two properties within each document. WHERE Id == "" AND Address.City == "" + // notice here how we are doing an equality comparison on the string value of City + + paramList = new SqlParameterList(); + paramList.add(new SqlParameter("@id", "AndersenFamily")); + paramList.add(new SqlParameter("@city", "Seattle")); + querySpec = new SqlQuerySpec( + "SELECT * FROM Families f WHERE f.id = @id AND f.Address.City = @city", + paramList); + + executeQueryWithQuerySpecPrintSingleResult(querySpec); } // Document delete From 5ff3b6e3f17d80d1f86409ba119228bfc112f6e5 Mon Sep 17 00:00:00 2001 From: Andrew Feldman Date: Fri, 15 May 2020 05:08:01 -0700 Subject: [PATCH 6/8] Autoscale container CRUD demo --- .../AutoscaleContainerCRUDQuickstart.java | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 src/main/java/com/azure/cosmos/examples/autoscalecontainercrud/sync/AutoscaleContainerCRUDQuickstart.java diff --git a/src/main/java/com/azure/cosmos/examples/autoscalecontainercrud/sync/AutoscaleContainerCRUDQuickstart.java b/src/main/java/com/azure/cosmos/examples/autoscalecontainercrud/sync/AutoscaleContainerCRUDQuickstart.java new file mode 100644 index 0000000..8ffcb2d --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/autoscalecontainercrud/sync/AutoscaleContainerCRUDQuickstart.java @@ -0,0 +1,195 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.examples.autoscalecontainercrud.sync; + +import com.azure.cosmos.ConsistencyLevel; +import com.azure.cosmos.CosmosClient; +import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosContainer; +import com.azure.cosmos.CosmosDatabase; +import com.azure.cosmos.CosmosPagedIterable; +import com.azure.cosmos.examples.changefeed.SampleChangeFeedProcessor; +import com.azure.cosmos.examples.common.AccountSettings; +import com.azure.cosmos.models.CosmosContainerProperties; +import com.azure.cosmos.models.CosmosContainerRequestOptions; +import com.azure.cosmos.models.CosmosContainerResponse; +import com.azure.cosmos.models.CosmosDatabaseRequestOptions; +import com.azure.cosmos.models.CosmosDatabaseResponse; +import com.azure.cosmos.models.FeedOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AutoscaleContainerCRUDQuickstart { + + private CosmosClient client; + + private final String databaseName = "AzureSampleFamilyDB"; + private final String containerName = "FamilyContainer"; + + private CosmosDatabase database; + private CosmosContainer container; + + protected static Logger logger = LoggerFactory.getLogger(SampleChangeFeedProcessor.class.getSimpleName()); + + public void close() { + client.close(); + } + + /** + * Sample to demonstrate the following AUTOSCALE container CRUD operations: + * -Create + * -Update throughput + * -Read by ID + * -Read all + * -Delete + */ + public static void main(String[] args) { + AutoscaleContainerCRUDQuickstart p = new AutoscaleContainerCRUDQuickstart(); + + try { + logger.info("Starting SYNC main"); + p.autoscaleContainerCRUDDemo(); + logger.info("Demo complete, please hold while resources are released"); + } catch (Exception e) { + e.printStackTrace(); + logger.error(String.format("Cosmos getStarted failed with %s", e)); + } finally { + logger.info("Closing the client"); + p.shutdown(); + } + } + + private void autoscaleContainerCRUDDemo() throws Exception { + + logger.info("Using Azure Cosmos DB endpoint: " + AccountSettings.HOST); + + // Create sync client + client = new CosmosClientBuilder() + .setEndpoint(AccountSettings.HOST) + .setKey(AccountSettings.MASTER_KEY) + .setConsistencyLevel(ConsistencyLevel.EVENTUAL) + .buildClient(); + + + createDatabaseIfNotExists(); + createContainerIfNotExists(); + + readContainerById(); + readAllContainers(); + // deleteAContainer() is called at shutdown() + + } + + // Database Create + private void createDatabaseIfNotExists() throws Exception { + logger.info("Create database " + databaseName + " if not exists..."); + + // Create database if not exists + database = client.createDatabaseIfNotExists(databaseName).getDatabase(); + + logger.info("Done."); + } + + // Container create + private void createContainerIfNotExists() throws Exception { + logger.info("Create autoscale container " + containerName + " if not exists."); + + // Container and autoscale throughput settings + CosmosContainerProperties autoscaleContainerProperties = new CosmosContainerProperties(containerName, "/lastName"); + ThroughputProperties autoscaleThroughputProperties = ThroughputProperties.createAutoscaledThroughput(200); //Set autoscale max RU/s + + // Create the container with autoscale enabled + container = database.createContainer(autoscaleContainerProperties, autoscaleThroughputProperties, + new CosmosContainerRequestOptions()).getContainer(); + + logger.info("Done."); + } + + // Update container throughput + private void updateContainerThroughput() throws Exception { + logger.info("Update autoscale max throughput for container " + containerName + "."); + + // Change the autoscale max throughput (RU/s) + container.replaceThroughput(ThroughputProperties.createAutoscaledThroughput(400)); + + logger.info("Done."); + } + + private void readContainerThroughput() throws Exception { + // Read the throughput on a resource + ThroughputProperties autoscaleContainerThroughput = container.readThroughput().getProperties(); + + // The autoscale max throughput (RU/s) of the resource + int autoscaleMaxThroughput = autoscaleContainerThroughput.getAutoscaleMaxThroughput(); + + // The throughput (RU/s) the resource is currently scaled to + int currentThroughput = autoscaleContainerThroughput.Throughput; + + logger.info("Autoscale max throughput: {} current throughput: {}",autoscaleMaxThroughput,currentThroughput); + } + + // Container read + private void readContainerById() throws Exception { + logger.info("Read container " + containerName + " by ID."); + + // Read container by ID + container = database.getContainer(containerName); + + logger.info("Done."); + } + + // Container read all + private void readAllContainers() throws Exception { + logger.info("Read all containers in database " + databaseName + "."); + + // Read all containers in the account + CosmosPagedIterable containers = database.readAllContainers(new FeedOptions()); + + // Print + String msg="Listing containers in database:\n"; + for(CosmosContainerProperties containerProps : containers) { + msg += String.format("-Container ID: %s\n",containerProps.getId()); + } + logger.info(msg + "\n"); + + logger.info("Done."); + } + + // Container delete + private void deleteAContainer() throws Exception { + logger.info("Delete container " + containerName + " by ID."); + + // Delete container + CosmosContainerResponse containerResp = database.getContainer(containerName).delete(new CosmosContainerRequestOptions()); + logger.info("Status code for container delete: {}",containerResp.getStatusCode()); + + logger.info("Done."); + } + + // Database delete + private void deleteADatabase() throws Exception { + logger.info("Last step: delete database " + databaseName + " by ID."); + + // Delete database + CosmosDatabaseResponse dbResp = client.getDatabase(databaseName).delete(new CosmosDatabaseRequestOptions()); + logger.info("Status code for database delete: {}",dbResp.getStatusCode()); + + logger.info("Done."); + } + + // Cleanup before close + private void shutdown() { + try { + //Clean shutdown + deleteAContainer(); + deleteADatabase(); + } catch (Exception err) { + logger.error("Deleting Cosmos DB resources failed, will still attempt to close the client. See stack trace below."); + err.printStackTrace(); + } + client.close(); + logger.info("Done with sample."); + } + +} From 778409ef528d49a327e7430936a4016394a7dd44 Mon Sep 17 00:00:00 2001 From: Andrew Feldman Date: Fri, 15 May 2020 05:10:46 -0700 Subject: [PATCH 7/8] Added autoscale database CRUD demo --- .../sync/AutoscaleDatabaseCRUDQuickstart.java | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 src/main/java/com/azure/cosmos/examples/autoscaledatabasecrud/sync/AutoscaleDatabaseCRUDQuickstart.java diff --git a/src/main/java/com/azure/cosmos/examples/autoscaledatabasecrud/sync/AutoscaleDatabaseCRUDQuickstart.java b/src/main/java/com/azure/cosmos/examples/autoscaledatabasecrud/sync/AutoscaleDatabaseCRUDQuickstart.java new file mode 100644 index 0000000..602913d --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/autoscaledatabasecrud/sync/AutoscaleDatabaseCRUDQuickstart.java @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.examples.autoscaledatabasecrud.sync; + +import com.azure.cosmos.ConsistencyLevel; +import com.azure.cosmos.CosmosClient; +import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosDatabase; +import com.azure.cosmos.CosmosPagedIterable; +import com.azure.cosmos.examples.changefeed.SampleChangeFeedProcessor; +import com.azure.cosmos.examples.common.AccountSettings; +import com.azure.cosmos.models.CosmosDatabaseProperties; +import com.azure.cosmos.models.CosmosDatabaseRequestOptions; +import com.azure.cosmos.models.CosmosDatabaseResponse; +import com.azure.cosmos.models.FeedOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AutoscaleDatabaseCRUDQuickstart { + + private CosmosClient client; + + private final String databaseName = "AzureSampleFamilyDB"; + + private CosmosDatabase database; + + protected static Logger logger = LoggerFactory.getLogger(SampleChangeFeedProcessor.class.getSimpleName()); + + public void close() { + client.close(); + } + + /** + * Sample to demonstrate the following AUTOSCALE database CRUD operations: + * -Create + * -Read by ID + * -Read all + * -Delete + */ + public static void main(String[] args) { + AutoscaleDatabaseCRUDQuickstart p = new AutoscaleDatabaseCRUDQuickstart(); + + try { + logger.info("Starting SYNC main"); + p.autoscaleDatabaseCRUDDemo(); + logger.info("Demo complete, please hold while resources are released"); + } catch (Exception e) { + e.printStackTrace(); + logger.error(String.format("Cosmos getStarted failed with %s", e)); + } finally { + logger.info("Closing the client"); + p.shutdown(); + } + } + + private void autoscaleDatabaseCRUDDemo() throws Exception { + + logger.info("Using Azure Cosmos DB endpoint: " + AccountSettings.HOST); + + // Create sync client + client = new CosmosClientBuilder() + .setEndpoint(AccountSettings.HOST) + .setKey(AccountSettings.MASTER_KEY) + .setConsistencyLevel(ConsistencyLevel.EVENTUAL) + .buildClient(); + + + createDatabaseIfNotExists(); + readDatabaseById(); + readAllDatabases(); + // deleteADatabase() is called at shutdown() + + } + + // Database Create + private void createDatabaseIfNotExists() throws Exception { + logger.info("Create database " + databaseName + " if not exists..."); + + // Autoscale throughput settings + ThroughputProperties autoscaleThroughputProperties = ThroughputProperties.createAutoscaledThroughput(400); //Set autoscale max RU/s + + //Create the database with autoscale enabled + CosmosDatabase database = client.createDatabase(databaseName, autoscaleThroughputProperties).getDatabase(); + + logger.info("Done."); + } + + // Database read + private void readDatabaseById() throws Exception { + logger.info("Read database " + databaseName + " by ID."); + + // Read database by ID + database = client.getDatabase(databaseName); + + logger.info("Done."); + } + + // Database read all + private void readAllDatabases() throws Exception { + logger.info("Read all databases in the account."); + + // Read all databases in the account + CosmosPagedIterable databases = client.readAllDatabases(new FeedOptions()); + + // Print + String msg="Listing databases in account:\n"; + for(CosmosDatabaseProperties dbProps : databases) { + msg += String.format("-Database ID: %s\n",dbProps.getId()); + } + logger.info(msg + "\n"); + + logger.info("Done."); + } + + // Database delete + private void deleteADatabase() throws Exception { + logger.info("Last step: delete database " + databaseName + " by ID."); + + // Delete database + CosmosDatabaseResponse dbResp = client.getDatabase(databaseName).delete(new CosmosDatabaseRequestOptions()); + logger.info("Status code for database delete: {}",dbResp.getStatusCode()); + + logger.info("Done."); + } + + // Cleanup before close + private void shutdown() { + try { + //Clean shutdown + deleteADatabase(); + } catch (Exception err) { + logger.error("Deleting Cosmos DB resources failed, will still attempt to close the client. See stack trace below."); + err.printStackTrace(); + } + client.close(); + logger.info("Done with sample."); + } + +} From de4aa7cd223a9920be17f9cdc578a8f86917eba9 Mon Sep 17 00:00:00 2001 From: Andrew Feldman Date: Fri, 15 May 2020 05:17:04 -0700 Subject: [PATCH 8/8] Analytical store sample --- .../AnalyticalContainerCRUDQuickstart.java | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 src/main/java/com/azure/cosmos/examples/analyticalcontainercrud/sync/AnalyticalContainerCRUDQuickstart.java diff --git a/src/main/java/com/azure/cosmos/examples/analyticalcontainercrud/sync/AnalyticalContainerCRUDQuickstart.java b/src/main/java/com/azure/cosmos/examples/analyticalcontainercrud/sync/AnalyticalContainerCRUDQuickstart.java new file mode 100644 index 0000000..fe73be1 --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/analyticalcontainercrud/sync/AnalyticalContainerCRUDQuickstart.java @@ -0,0 +1,184 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.examples.analyticalcontainercrud.sync; + +import com.azure.cosmos.ConsistencyLevel; +import com.azure.cosmos.CosmosClient; +import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosContainer; +import com.azure.cosmos.CosmosDatabase; +import com.azure.cosmos.CosmosPagedIterable; +import com.azure.cosmos.examples.changefeed.SampleChangeFeedProcessor; +import com.azure.cosmos.examples.common.AccountSettings; +import com.azure.cosmos.models.CosmosContainerProperties; +import com.azure.cosmos.models.CosmosContainerRequestOptions; +import com.azure.cosmos.models.CosmosContainerResponse; +import com.azure.cosmos.models.CosmosDatabaseRequestOptions; +import com.azure.cosmos.models.CosmosDatabaseResponse; +import com.azure.cosmos.models.FeedOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AnalyticalContainerCRUDQuickstart { + + private CosmosClient client; + + private final String databaseName = "AzureSampleFamilyDB"; + private final String containerName = "FamilyContainer"; + + private CosmosDatabase database; + private CosmosContainer container; + + protected static Logger logger = LoggerFactory.getLogger(SampleChangeFeedProcessor.class.getSimpleName()); + + public void close() { + client.close(); + } + + /** + * Sample to demonstrate the following ANALYTICAL STORE container CRUD operations: + * -Create + * -Update throughput + * -Read by ID + * -Read all + * -Delete + */ + public static void main(String[] args) { + AnalyticalContainerCRUDQuickstart p = new AnalyticalContainerCRUDQuickstart(); + + try { + logger.info("Starting SYNC main"); + p.containerCRUDDemo(); + logger.info("Demo complete, please hold while resources are released"); + } catch (Exception e) { + e.printStackTrace(); + logger.error(String.format("Cosmos getStarted failed with %s", e)); + } finally { + logger.info("Closing the client"); + p.shutdown(); + } + } + + private void containerCRUDDemo() throws Exception { + + logger.info("Using Azure Cosmos DB endpoint: " + AccountSettings.HOST); + + // Create sync client + client = new CosmosClientBuilder() + .setEndpoint(AccountSettings.HOST) + .setKey(AccountSettings.MASTER_KEY) + .setConsistencyLevel(ConsistencyLevel.EVENTUAL) + .buildClient(); + + + createDatabaseIfNotExists(); + createContainerIfNotExists(); + + readContainerById(); + readAllContainers(); + // deleteAContainer() is called at shutdown() + + } + + // Database Create + private void createDatabaseIfNotExists() throws Exception { + logger.info("Create database " + databaseName + " if not exists..."); + + // Create database if not exists + database = client.createDatabaseIfNotExists(databaseName).getDatabase(); + + logger.info("Done."); + } + + // Container create + private void createContainerIfNotExists() throws Exception { + logger.info("Create container " + containerName + " if not exists."); + + // Create container if not exists + CosmosContainerProperties containerProperties = + new CosmosContainerProperties(containerName, "/lastName"); + + // Set analytical store properties + containerProperties.setAnalyticalStoreTimeToLiveInSeconds(-1); + + // Create container with 200 RU/s + container = database.createContainerIfNotExists(containerProperties, 200).getContainer(); + + logger.info("Done."); + } + + // Update container throughput + private void updateContainerThroughput() throws Exception { + logger.info("Update throughput for container " + containerName + "."); + + // Specify new throughput value + container.replaceProvisionedThroughput(400); + + logger.info("Done."); + } + + // Container read + private void readContainerById() throws Exception { + logger.info("Read container " + containerName + " by ID."); + + // Read container by ID + container = database.getContainer(containerName); + + logger.info("Done."); + } + + // Container read all + private void readAllContainers() throws Exception { + logger.info("Read all containers in database " + databaseName + "."); + + // Read all containers in the account + CosmosPagedIterable containers = database.readAllContainers(new FeedOptions()); + + // Print + String msg="Listing containers in database:\n"; + for(CosmosContainerProperties containerProps : containers) { + msg += String.format("-Container ID: %s\n",containerProps.getId()); + } + logger.info(msg + "\n"); + + logger.info("Done."); + } + + // Container delete + private void deleteAContainer() throws Exception { + logger.info("Delete container " + containerName + " by ID."); + + // Delete container + CosmosContainerResponse containerResp = database.getContainer(containerName).delete(new CosmosContainerRequestOptions()); + logger.info("Status code for container delete: {}",containerResp.getStatusCode()); + + logger.info("Done."); + } + + // Database delete + private void deleteADatabase() throws Exception { + logger.info("Last step: delete database " + databaseName + " by ID."); + + // Delete database + CosmosDatabaseResponse dbResp = client.getDatabase(databaseName).delete(new CosmosDatabaseRequestOptions()); + logger.info("Status code for database delete: {}",dbResp.getStatusCode()); + + logger.info("Done."); + } + + // Cleanup before close + private void shutdown() { + try { + //Clean shutdown + deleteAContainer(); + deleteADatabase(); + } catch (Exception err) { + logger.error("Deleting Cosmos DB resources failed, will still attempt to close the client. See stack trace below."); + err.printStackTrace(); + } + client.close(); + logger.info("Done with sample."); + } + +}