Querying Items with Azure Cosmos DB SDK for Java
This tutorial demonstrates how to query items from your Azure Cosmos DB container using the Azure Cosmos DB SDK for Java. We'll cover various querying techniques, including point reads, complex queries with SQL, and leveraging change feed.
Prerequisite: Ensure you have a working Azure Cosmos DB account and a container with some data. If you haven't set this up, please refer to the Create an Azure Cosmos DB account and Quick start guide.
1. Setting up the SDK
First, make sure you have the Azure Cosmos DB Java SDK added to your project's dependencies. If you're using Maven, add the following to your pom.xml:
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-cosmos</artifactId>
<version>4.40.0</version><!-- Check for the latest version -->
</dependency>
2. Establishing a Connection
Before querying, you need to establish a connection to your Cosmos DB endpoint. This typically involves creating a CosmosClient instance.
import com.azure.cosmos.CosmosClient;
import com.azure.cosmos.CosmosClientBuilder;
import com.azure.cosmos.CosmosDatabase;
import com.azure.cosmos.CosmosContainer;
// Replace with your actual endpoint and key
String endpoint = "YOUR_COSMOS_DB_ENDPOINT";
String key = "YOUR_COSMOS_DB_PRIMARY_KEY";
String databaseId = "YOUR_DATABASE_ID";
String containerId = "YOUR_CONTAINER_ID";
CosmosClient client = new CosmosClientBuilder()
.endpoint(endpoint)
.key(key)
.buildClient();
CosmosDatabase database = client.getDatabase(databaseId);
CosmosContainer container = database.getContainer(containerId);
System.out.println("Connected to Cosmos DB.");
3. Querying with SQL
The most common way to query data in Azure Cosmos DB is by using SQL queries. The SDK provides methods to execute these queries against your container.
3.1 Basic SQL Query
To retrieve all items that match a specific condition:
import com.azure.cosmos.models.CosmosQueryRequestOptions;
import com.azure.cosmos.models.SqlParameter;
import com.azure.cosmos.models.SqlParametersList;
import com.azure.cosmos.util.CosmosPagedIterable;
import com.fasterxml.jackson.databind.JsonNode;
String query = "SELECT * FROM c WHERE c.category = @category";
CosmosQueryRequestOptions options = new CosmosQueryRequestOptions();
options.setPartitionKey(new PartitionKey("exampleCategory")); // Optional: Specify partition key for efficiency
SqlParametersList parameters = SqlParametersList.of(new SqlParameter("@category", "Electronics"));
options.setQueryMetricsEnabled(true);
CosmosPagedIterable<JsonNode> results = container.queryItems(query, parameters, JsonNode.class, options);
System.out.println("Query results:");
results.forEach(item -> {
System.out.println(" - " + item.toString());
});
// Access query metrics if enabled
results.iterable().forEach(page -> {
System.out.println("Request charge for page: " + page.getCosmosDiagnostics().getRequestCharge());
});
3.2 Querying with Parameters
Using parameters is highly recommended to prevent SQL injection and improve query performance.
String queryWithParams = "SELECT VALUE r.name FROM r WHERE r.status = @status AND r.priority >= @priority";
CosmosQueryRequestOptions optionsWithParams = new CosmosQueryRequestOptions();
SqlParametersList paramsList = SqlParametersList.of(
new SqlParameter("@status", "Active"),
new SqlParameter("@priority", 5)
);
CosmosPagedIterable<String> names = container.queryItems(queryWithParams, paramsList, String.class, optionsWithParams);
System.out.println("\nItem names with Active status and priority >= 5:");
names.forEach(name -> System.out.println(" - " + name));
3.3 Limiting Results and Pagination
You can limit the number of results returned and implement pagination to handle large datasets.
String limitQuery = "SELECT TOP 10 * FROM c";
CosmosQueryRequestOptions limitOptions = new CosmosQueryRequestOptions();
limitOptions.setLimit(10); // Not strictly needed with TOP 10 in SQL, but good practice for some scenarios
CosmosPagedIterable<JsonNode> topItems = container.queryItems(limitQuery, JsonNode.class, limitOptions);
System.out.println("\nTop 10 items:");
topItems.forEach(item -> System.out.println(" - " + item.get("id").asText()));
// Pagination example (using continuation tokens)
CosmosQueryRequestOptions paginationOptions = new CosmosQueryRequestOptions();
paginationOptions.setPageSizeHint(100); // Suggest a page size
CosmosPagedIterable<JsonNode> firstPage = container.queryItems("SELECT * FROM c", JsonNode.class, paginationOptions);
System.out.println("\nFirst page of items:");
firstPage.forEach(item -> System.out.println(" - " + item.get("id").asText()));
if (firstPage.hasMoreResults()) {
paginationOptions.setContinuationToken(firstPage.getContinuationToken());
CosmosPagedIterable<JsonNode> secondPage = container.queryItems("SELECT * FROM c", JsonNode.class, paginationOptions);
System.out.println("Second page of items:");
secondPage.forEach(item -> System.out.println(" - " + item.get("id").asText()));
}
4. Point Reads
For retrieving a single item by its ID and partition key, a point read is much more efficient than a query.
import com.azure.cosmos.models.PartitionKey;
import com.azure.cosmos.models.CosmosItemResponse;
String itemId = "your-item-id"; // The ID of the item to retrieve
String partitionKey = "your-partition-key"; // The partition key of the item
try {
CosmosItemResponse response = container.readItem(itemId, new PartitionKey(partitionKey), JsonNode.class);
JsonNode item = response.getItem();
System.out.println("\nRetrieved item by ID: " + item.toString());
System.out.println("Item ETag: " + response.getETag());
} catch (Exception e) {
System.err.println("Error reading item: " + e.getMessage());
}
5. Change Feed Queries
The change feed allows you to track changes to items in your container. You can query for changes since a specific point in time or a continuation token.
import com.azure.cosmos.models.ChangeFeedPolicy;
import com.azure.cosmos.models.ChangeFeedOptions;
// Assuming you have established connection as before...
ChangeFeedOptions options = new ChangeFeedOptions();
options.setPageSizeHint(100); // Optional: hint for page size
// To get changes since the beginning (first time) or a specific point
// options.setStartTime(java.time.OffsetDateTime.now().minusHours(1)); // Example: last hour
CosmosPagedIterable<JsonNode> changes = container.queryChangeFeed(JsonNode.class, options);
System.out.println("\nChange feed items:");
changes.forEach(change -> {
System.out.println(" - Changed item ID: " + change.get("id").asText());
// You can inspect change.get("_ts") for timestamp if needed
});
// To continue reading from where you left off, use the continuation token:
// String continuationToken = changes.getContinuationToken();
// if (continuationToken != null) {
// options.setContinuationToken(continuationToken);
// CosmosPagedIterable<JsonNode> moreChanges = container.queryChangeFeed(JsonNode.class, options);
// // Process moreChanges...
// }
6. Best Practices
Always use parameterized queries to prevent SQL injection and improve performance.
When retrieving a single item, use point reads (
readItem) instead of SQL queries for better efficiency.Leverage partition keys in your SQL queries for improved throughput and reduced cost, especially in distributed scenarios.
Monitor your request charges and optimize queries to stay within your provisioned throughput.
For large result sets, implement pagination using continuation tokens.
Tip: The Azure Cosmos DB emulator is a great tool for local development and testing your queries without incurring cloud costs.
This tutorial covered the essential aspects of querying items in Azure Cosmos DB using the Java SDK. Explore the SDK documentation for more advanced querying capabilities and options.
Azure Cosmos DB, Java SDK, Query Items, SQL Query, Point Read, Change Feed, Azure Documentation, Tutorial, Database