Amazon DynamoDB
開発者ガイド (API バージョン 2012-08-10)

テーブルおよびインデックスにクエリを実行: .NET

Query オペレーションを使用すると、テーブルまたは セカンダリインデックス をクエリできます。この関数ではパーティションキー値と等価条件を指定する必要があります。テーブルまたはインデックスにソートキーがある場合は、ソートキー値と条件を指定することで結果を絞り込むことができます。

次に、低レベル .NET SDK API を使用してテーブルのクエリを行うステップを示します。

  1. AmazonDynamoDBClient クラスのインスタンスを作成します。

  2. QueryRequest クラスのインスタンスを作成して、クエリオペレーションパラメータを指定します。

  3. Query メソッドを実行し、前述のステップで作成した QueryRequest オブジェクトを指定します。

    応答には、クエリによって返されたすべての項目を示す QueryResult オブジェクトが含まれています。

次の C# コードスニペットは、前述のタスクの例です。このスニペットでは、フォーラムスレッドの返信を格納する Reply テーブルがあることを前提としています。詳細については、「テーブルの作成とサンプルデータのロード」を参照してください。

Reply Id, ReplyDateTime, ... )

各フォーラムスレッドには一意の ID があり、0 またはそれ以上の返信を受け取ることができます。したがってプライマリキーは、Id (パーティションキー) と ReplyDateTime (ソートキー) の両方で構成されます。

次のクエリでは、特定のスレッド件名に対するすべての返信を取り出します。このクエリでは、テーブル名と件名の両方が必要になります。

AmazonDynamoDBClient client = new AmazonDynamoDBClient(); var request = new QueryRequest { TableName = "Reply", KeyConditionExpression = "Id = :v_Id", ExpressionAttributeValues = new Dictionary<string, AttributeValue> { {":v_Id", new AttributeValue { S = "Amazon DynamoDB#DynamoDB Thread 1" }}} }; var response = client.Query(request); foreach (Dictionary<string, AttributeValue> item in response.Items) { // Process the result. PrintItem(item); }

オプションパラメータの指定

Query メソッドでは、複数のオプションパラメータがサポートされています。たとえば、必要に応じて条件を指定して前述のクエリの結果を絞り込み、過去 2 週間の返信が返されるようにできます。この条件をソートキー条件と呼びます。指定したクエリ条件が Amazon DynamoDB によってプライマリキーのソートキーに対して評価されるためです。その他のオプションパラメータを指定して、クエリ結果の項目から特定の属性のリストだけを取り出すこともできます。詳細については、「Query」を参照してください。

次の C# コードスニペットでは、過去 15 日間に投稿されたフォーラムスレッドの返信が取り出されます。このスニペットでは、次のオプションパラメータが指定されています。

  • 過去 15 日間の返信だけを取り出す KeyConditionExpression

  • クエリ結果内の項目について取得する属性のリストを指定する ProjectionExpression パラメータ。

  • 強力な整合性のある読み込みを実行する ConsistentRead パラメータ。

DateTime twoWeeksAgoDate = DateTime.UtcNow - TimeSpan.FromDays(15); string twoWeeksAgoString = twoWeeksAgoDate.ToString(AWSSDKUtils.ISO8601DateFormat); var request = new QueryRequest { TableName = "Reply", KeyConditionExpression = "Id = :v_Id and ReplyDateTime > :v_twoWeeksAgo", ExpressionAttributeValues = new Dictionary<string, AttributeValue> { {":v_Id", new AttributeValue { S = "Amazon DynamoDB#DynamoDB Thread 2" }}, {":v_twoWeeksAgo", new AttributeValue { S = twoWeeksAgoString }} }, ProjectionExpression = "Subject, ReplyDateTime, PostedBy", ConsistentRead = true }; var response = client.Query(request); foreach (Dictionary<string, AttributeValue> item in response.Items) { // Process the result. PrintItem(item); }

また、オプションの Limit パラメータを追加することで、ページサイズ、またはページあたりの項目数を制限することもできます。Query メソッドを実行するたびに、指定された数の項目が含まれる結果が 1 ページ取得されます。次のページをフェッチするには、前ページの最後の項目のプライマリキーの値を入力して次の項目のセットが返されるようにし、Query メソッドを再度実行します。この情報は、ExclusiveStartKey プロパティを設定することでリクエストに含めます。このプロパティは最初は null である場合があります。以降のページを取り出すには、このプロパティ値を更新して、前ページの最後の項目のプライマリキーにする必要があります。

次の C# コードスニペットでは、Reply テーブルのクエリを実行しています。リクエストでは、オプションの Limit および ExclusiveStartKey パラメータを指定しています。do/while ループは、LastEvaluatedKey から null 値が返されるまで、一度に 1 ページのスキャンを継続します。

Dictionary<string,AttributeValue> lastKeyEvaluated = null; do { var request = new QueryRequest { TableName = "Reply", KeyConditionExpression = "Id = :v_Id", ExpressionAttributeValues = new Dictionary<string, AttributeValue> { {":v_Id", new AttributeValue { S = "Amazon DynamoDB#DynamoDB Thread 2" }} }, // Optional parameters. Limit = 1, ExclusiveStartKey = lastKeyEvaluated }; var response = client.Query(request); // Process the query result. foreach (Dictionary<string, AttributeValue> item in response.Items) { PrintItem(item); } lastKeyEvaluated = response.LastEvaluatedKey; } while (lastKeyEvaluated != null && lastKeyEvaluated.Count != 0);

例 – AWS SDK for .NET を使用したクエリ

以下のテーブルには、フォーラムのコレクションに関する情報が格納されています。詳細については、「テーブルの作成とサンプルデータのロード」を参照してください。

Forum ( Name, ... ) Thread ( ForumName, Subject, Message, LastPostedBy, LastPostDateTime, ...) Reply ( Id, ReplyDateTime, Message, PostedBy, ...)

この C# コード例では、「DynamoDB」フォーラムで「DynamoDB Thread 1」スレッドに対する返信を検索するのバリエーションを実行します。

  • スレッドに対する返信を検索します。

  • スレッドに対する返信を検索します。Limit クエリパラメータを指定してページサイズを設定します。

    この機能は、ページ分割を使用した、複数ページのクエリ結果の処理を示しています。Amazon DynamoDB にはページサイズ制限があり、結果がページサイズを超えた場合には、結果のうち最初の 1 ページ分だけが得られます。このコーディングパターンによって、確実にクエリ結果の全ページがコードで処理されます。

  • 過去 15 日間の返信を検索します。

  • 特定の日付範囲の返信を検索します。

    前述の 2 つのクエリはどちらも、ソートキー条件を指定してクエリ結果を絞り込む方法、必要に応じてその他のクエリパラメーターを使用する方法を示しています。

次のサンプルをテストするための詳しい手順については、「.NET コードサンプル」を参照してください。

using System; using System.Collections.Generic; using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.Model; using Amazon.Runtime; using Amazon.Util; namespace com.amazonaws.codesamples { class LowLevelQuery { private static AmazonDynamoDBClient client = new AmazonDynamoDBClient(); static void Main(string[] args) { try { // Query a specific forum and thread. string forumName = "Amazon DynamoDB"; string threadSubject = "DynamoDB Thread 1"; FindRepliesForAThread(forumName, threadSubject); FindRepliesForAThreadSpecifyOptionalLimit(forumName, threadSubject); FindRepliesInLast15DaysWithConfig(forumName, threadSubject); FindRepliesPostedWithinTimePeriod(forumName, threadSubject); Console.WriteLine("Example complete. To continue, press Enter"); Console.ReadLine(); } catch (AmazonDynamoDBException e) { Console.WriteLine(e.Message); Console.ReadLine(); } catch (AmazonServiceException e) { Console.WriteLine(e.Message); Console.ReadLine(); } catch (Exception e) { Console.WriteLine(e.Message); Console.ReadLine(); } } private static void FindRepliesPostedWithinTimePeriod(string forumName, string threadSubject) { Console.WriteLine("*** Executing FindRepliesPostedWithinTimePeriod() ***"); string replyId = forumName + "#" + threadSubject; // You must provide date value based on your test data. DateTime startDate = DateTime.UtcNow - TimeSpan.FromDays(21); string start = startDate.ToString(AWSSDKUtils.ISO8601DateFormat); // You provide date value based on your test data. DateTime endDate = DateTime.UtcNow - TimeSpan.FromDays(5); string end = endDate.ToString(AWSSDKUtils.ISO8601DateFormat); var request = new QueryRequest { TableName = "Reply", ReturnConsumedCapacity = "TOTAL", KeyConditionExpression = "Id = :v_replyId and ReplyDateTime between :v_start and :v_end", ExpressionAttributeValues = new Dictionary<string, AttributeValue> { {":v_replyId", new AttributeValue { S = replyId }}, {":v_start", new AttributeValue { S = start }}, {":v_end", new AttributeValue { S = end }} } }; var response = client.Query(request); Console.WriteLine("\nNo. of reads used (by query in FindRepliesPostedWithinTimePeriod) {0}", response.ConsumedCapacity.CapacityUnits); foreach (Dictionary<string, AttributeValue> item in response.Items) { PrintItem(item); } Console.WriteLine("To continue, press Enter"); Console.ReadLine(); } private static void FindRepliesInLast15DaysWithConfig(string forumName, string threadSubject) { Console.WriteLine("*** Executing FindRepliesInLast15DaysWithConfig() ***"); string replyId = forumName + "#" + threadSubject; DateTime twoWeeksAgoDate = DateTime.UtcNow - TimeSpan.FromDays(15); string twoWeeksAgoString = twoWeeksAgoDate.ToString(AWSSDKUtils.ISO8601DateFormat); var request = new QueryRequest { TableName = "Reply", ReturnConsumedCapacity = "TOTAL", KeyConditionExpression = "Id = :v_replyId and ReplyDateTime > :v_interval", ExpressionAttributeValues = new Dictionary<string, AttributeValue> { {":v_replyId", new AttributeValue { S = replyId }}, {":v_interval", new AttributeValue { S = twoWeeksAgoString }} }, // Optional parameter. ProjectionExpression = "Id, ReplyDateTime, PostedBy", // Optional parameter. ConsistentRead = true }; var response = client.Query(request); Console.WriteLine("No. of reads used (by query in FindRepliesInLast15DaysWithConfig) {0}", response.ConsumedCapacity.CapacityUnits); foreach (Dictionary<string, AttributeValue> item in response.Items) { PrintItem(item); } Console.WriteLine("To continue, press Enter"); Console.ReadLine(); } private static void FindRepliesForAThreadSpecifyOptionalLimit(string forumName, string threadSubject) { Console.WriteLine("*** Executing FindRepliesForAThreadSpecifyOptionalLimit() ***"); string replyId = forumName + "#" + threadSubject; Dictionary<string, AttributeValue> lastKeyEvaluated = null; do { var request = new QueryRequest { TableName = "Reply", ReturnConsumedCapacity = "TOTAL", KeyConditionExpression = "Id = :v_replyId", ExpressionAttributeValues = new Dictionary<string, AttributeValue> { {":v_replyId", new AttributeValue { S = replyId }} }, Limit = 2, // The Reply table has only a few sample items. So the page size is smaller. ExclusiveStartKey = lastKeyEvaluated }; var response = client.Query(request); Console.WriteLine("No. of reads used (by query in FindRepliesForAThreadSpecifyLimit) {0}\n", response.ConsumedCapacity.CapacityUnits); foreach (Dictionary<string, AttributeValue> item in response.Items) { PrintItem(item); } lastKeyEvaluated = response.LastEvaluatedKey; } while (lastKeyEvaluated != null && lastKeyEvaluated.Count != 0); Console.WriteLine("To continue, press Enter"); Console.ReadLine(); } private static void FindRepliesForAThread(string forumName, string threadSubject) { Console.WriteLine("*** Executing FindRepliesForAThread() ***"); string replyId = forumName + "#" + threadSubject; var request = new QueryRequest { TableName = "Reply", ReturnConsumedCapacity = "TOTAL", KeyConditionExpression = "Id = :v_replyId", ExpressionAttributeValues = new Dictionary<string, AttributeValue> { {":v_replyId", new AttributeValue { S = replyId }} } }; var response = client.Query(request); Console.WriteLine("No. of reads used (by query in FindRepliesForAThread) {0}\n", response.ConsumedCapacity.CapacityUnits); foreach (Dictionary<string, AttributeValue> item in response.Items) { PrintItem(item); } Console.WriteLine("To continue, press Enter"); Console.ReadLine(); } private static void PrintItem( Dictionary<string, AttributeValue> attributeList) { foreach (KeyValuePair<string, AttributeValue> kvp in attributeList) { string attributeName = kvp.Key; AttributeValue value = kvp.Value; Console.WriteLine( attributeName + " " + (value.S == null ? "" : "S=[" + value.S + "]") + (value.N == null ? "" : "N=[" + value.N + "]") + (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") + (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]") ); } Console.WriteLine("************************************************"); } } }