表および索引の作成

表および索引の作成方法について学習します。

表の作成は、アプリケーション開発の最初のステップです。

DDL文の例を次に示します。

/* Create a new table called users */
CREATE TABLE IF NOT EXISTS users(id INTEGER,
 name STRING,
 PRIMARY KEY(id))

/* Create a new table called users and set the TTL value to 4 days */
CREATE TABLE IF NOT EXISTS users(id INTEGER,
 name STRING,
 PRIMARY KEY(id))
USING TTL 4 days

/* Create a new multi-region table called users with two regions, and set the TTL value to 4 days */
CREATE TABLE users(
 id INTEGER,
 name STRING,
 team STRING,
 primary key(id))
USING TTL 4 DAYS IN REGIONS fra, lnd

/* Create a new index called nameIdx on the name field in the users table */
CREATE INDEX IF NOT EXISTS nameIdx ON users(name)

TableRequestとそのメソッドを使用して、表と索引を作成します。TableRequestクラスを使用すると、DDL文をTableRequest.setStatementメソッドに渡すことができます。

/* Create a simple table with an integer key and a single json data
 * field  and set your desired table capacity.
 * Set the table TTL value to 3 days.
 */
String createTableDDL = "CREATE TABLE IF NOT EXISTS users " +
 "(id INTEGER, name STRING, " +
 "PRIMARY KEY(id)) USING TTL 3 days";


TableRequest treq = new TableRequest().setStatement(createTableDDL);

// start the asynchronous operation
TableResult tres = handle.tableRequest(treq);


// The table request is asynchronous, so wait for the table to become active.
TableResult.waitForState(handle, tres.getTableName(),
 TableResult.State.ACTIVE,
 60000, // wait for 60 sec
 1000); // delay in ms for poll
 
// Create an index called nameIdx on the name field in the users table.
treq = new TableRequest().setStatement("CREATE INDEX 
  IF NOT EXISTS nameIdx ON users(name)
  ");

// start the asynchronous operation
  handle.tableRequest(treq);

子表の作成: APIクラスおよびメソッドを使用して、DDL文を実行して子表を作成します。子表の作成時に、子表が親表の制限を継承するため、表の制限を明示的に設定する必要はありません。
final static String tableName = "users";
final static String childtableName = "userDetails";
String createchildTableDDL = "CREATE TABLE IF NOT EXISTS " +
            tableName + "."+ childtableName + "(address STRING, salary INTEGER, " +
            "PRIMARY KEY(address))";
    TableRequest treq = new TableRequest().setStatement(createchildTableDDL);
    System.out.println("Creating child table " + tableName);
    TableResult tres = handle.tableRequest(treq);
    /* The request is async,
    * so wait for the table to become active.
    */
    System.out.println("Waiting for "+ childtableName + " to become active");
    tres.waitForCompletion(handle, 60000, /* wait 60 sec */
         1000); /* delay ms for poll */
    System.out.println("Table " + childtableName + " is active");

表の一覧を検索します:

表の一覧を取得できます。
ListTablesRequest tablereq = new ListTablesRequest();
String [] tablelis = handle.listTables(tablereq).getTables();
if (tablelis.length == 0)   
   System.out.println("No tables avaiable");
else {  
   System.out.println("The tables available are");   
   for (int i=0;i< tablelis.length; i++)  {    
      System.out.println(tablelis[i]);  
   }
}
表のスキーマもいつでもフェッチできます。
GetTableRequest gettblreq = new GetTableRequest();
gettblreq.setTableName(tableName);
System.out.println("The schema details for the table is " 
+ handle.getTable(gettblreq).getSchema());
DDL文は、borneo.TableRequestクラスを使用して実行されます。borneo.NoSQLHandle.table_request()へのすべてのコールは非同期であるため、結果を確認し、borneo.TableResult.wait_for_completion()をコールして操作が完了するまで待機する必要があります。
#Create a simple table with an integer key and a single 
#json data field and set your desired table capacity. 
#Set the table TTL value to 3 days.
from borneo import TableLimits,
TableRequest statement = 'create table if not exists users(id integer, 
                                              name string,
                                              ' + 'primary key(id) 
                                                 USING TTL 3 DAYS'

request = TableRequest().set_statement(statement)
# assume that a handle has been created, as handle, make the request 
#wait for 60 seconds, polling every 1 seconds
result = handle.do_table_request(request, 60000, 1000) 
# the above call to do_table_request is equivalent to 
# result = handle.table_request(request)
result.wait_for_completion(handle, 60000, 1000)
#Create an index called nameIdx on the name field in the users table.
request = TableRequest().set_statement("CREATE INDEX IF NOT EXISTS nameIdx 
                                        ON users(name)")
# assume that a handle has been created, as handle, make the request 
#wait for 60 seconds, polling every 1 seconds
result = handle.do_table_request(request, 60000, 1000) 
# the above call to do_table_request is equivalent to
# result = handle.table_request(request) 
result.wait_for_completion(handle, 60000, 1000)
子表の作成: APIクラスおよびメソッドを使用して、DDL文を実行して子表を作成します。子表の作成時に、子表が親表の制限を継承するため、表の制限を明示的に設定する必要はありません。
statement = 'create table if not exists users.userDetails (address STRING,
salary integer,  primary key(address))'
    print('Creating table: ' + statement)
    request = TableRequest().set_statement(statement)
    # Ask the cloud service to create the table, 
    # waiting for a total of 40000 milliseconds and polling the service 
    # every 3000 milliseconds to see if the table is active
    table_result = handle.do_table_request(request, 40000, 3000)
    table_result.wait_for_completion(handle, 40000, 3000)
    if (table_result.get_state() != State.ACTIVE):
        raise NameError('Table userDetails is in an unexpected state ' + 
str(table_result.get_state()))

表の一覧を検索します:

表の一覧を取得できます。
ltr = ListTablesRequest()
list(str)= handle.list_tables(ltr).getTables()
if list(str).len() = 0 
   print ("No tables available")
else 
   print('The tables available are: ' + list(str))
表のスキーマもいつでもフェッチできます。
request = GetTableRequest().set_table_name(table_name)
result = handle.get_table(request)
print('The schema details for the table is: ' + result.get_schema())
次の例では、整数キーと単一のSTRINGフィールドを持つ単純な表を作成します。表の作成リクエストは非同期です。表の作成が完了するまで待機します。
// Create a simple table with an integer key and a single
// json data field and set your desired table capacity.
// Set the table TTL value to 3 days.
tableName := "users"
stmt := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s "+
    "(id integer, name STRING, PRIMARY KEY(id) "+
    "USING TTL 3 DAYS)", tableName)

tableReq := &nosqldb.TableRequest{
    Statement: stmt, }
tableRes, err := client.DoTableRequest(tableReq)
if err != nil {
    fmt.Printf("cannot initiate CREATE TABLE request: %v\n", err)
    return
}
_, err = tableRes.WaitForCompletion(client, 60*time.Second, time.Second)
if err != nil {
    fmt.Printf("Error finishing CREATE TABLE request: %v\n", err)
    return
}
fmt.Println("Created table ", tableName)
//Create an index called nameIdx on the name field in the users table
stmt_ind := fmt.Sprintf("CREATE INDEX IF NOT EXISTS nameIdx ON users(name)")
tableReq := &nosqldb.TableRequest{Statement: stmt_ind}
tableRes, err := client.DoTableRequest(tableReq)
if err != nil {
    fmt.Printf("cannot initiate CREATE INDEX request: %v\n", err)
    return
}
_, err = tableRes.WaitForCompletion(client, 60*time.Second, time.Second)
if err != nil {
    fmt.Printf("Error finishing CREATE INDEX request: %v\n", err)
    return
}
fmt.Println("Created index nameIdx ")
子表の作成: APIクラスおよびメソッドを使用して、DDL文を実行して子表を作成します。子表の作成時に、子表が親表の制限を継承するため、表の制限を明示的に設定する必要はありません。
// Creates a simple child table with a string key and a single integer field.
    childtableName := "users.userDetails"
    stmt1 := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s ("+
    "address STRING, "+
    "salary INTEGER, "+
    "PRIMARY KEY(address))",
    childtableName)
    tableReq1 := &nosqldb.TableRequest{Statement: stmt1}
    tableRes1, err := client.DoTableRequest(tableReq1)
    if err != nil {
        fmt.Printf("cannot initiate CREATE TABLE request: %v\n", err)
        return
    }
    // The create table request is asynchronous, wait for table creation to complete.
    _, err = tableRes1.WaitForCompletion(client, 60*time.Second, time.Second)
    if err != nil {
        fmt.Printf("Error finishing CREATE TABLE request: %v\n", err)
        return
    }
    fmt.Println("Created table ", childtableName)

表の一覧を検索します:

表の一覧を取得できます。
req := &nosqldb.ListTablesRequest{Timeout: 3 * time.Second,}
res, err := client.ListTables(req)
if len(res.Tables)== 0{
   fmt.Printf("No tables in the given compartment"
   return
}
fmt.Printf("The tables in the given compartment are:\n" )
for i, table := range res.Tables {
   fmt.Printf(table)
}
表のスキーマもいつでもフェッチできます。
req := &nosqldb.GetTableRequest{
TableName: table_name, Timeout: 3 * time.Second, }
res, err := client.GetTable(req)
fmt.Printf("The schema details for the table is:state=%s, 
   limits=%v\n", res.State,res.Limits)

表DDL文は、tableDDLメソッドによって実行されます。NoSQLClientクラスの他のほとんどのメソッドと同様に、このメソッドは非同期で、TableResultのPromiseを返します。TableResultは、DDL操作のステータス(TableState、名前、スキーマ、TableLimitなど)を含むプレーンJavaScriptオブジェクトです。

tableDDLメソッドは、指定されたDDL操作のみを基礎となるストアで起動し、完了を待機しないことに注意してください。結果のTableResultは、通常、TableState.CREATINGTableState.DROPPINGTableState.UPDATINGなどの中間表の状態の1つを持ちます(後者は、表がALTER TABLE文によって変更されるプロセス中であるか、表の制限が変更されているか、その索引のいずれかが作成または削除されている場合に発生します)。

基礎となる操作が完了すると、表の状態がTableState.ACTIVEまたはTableState.DROPPEDに変更されます(DDL操作がDROP TABLEだった場合は後者)。
const NoSQLClient = require('oracle-nosqldb').NoSQLClient;
const TableState = require('oracle-nosqldb').TableState;
const client = new NoSQLClient('config.json');

async function createUsersTable() {
    try {
        const statement = 'CREATE TABLE IF NOT EXISTS users(id INTEGER, ' +
            'name STRING, PRIMARY KEY(id))';

let result = await client.tableDDL(statement);
        result = await client.forCompletion(result);
        console.log('Table users created');
    } catch(error) {
        //handle errors
    }
}
前述のコールが返されると、結果は操作の最終状態を反映します。または、完全なオプションを使用するには、前述のtry-catchブロックのコードを次のように置き換えます。
const statement = 'CREATE TABLE IF NOT EXISTS users(id INTEGER, ' +
        'name STRING, PRIMARY KEY(id))';

let result = await client.tableDDL(statement,
        complete: true
    });
    console.log('Table users created');
// Create an index called nameIdx on the name field in the users table.
try {
   const statement = 'CREATE INDEX IF NOT EXISTS nameIdx ON users(name))';
   let result = await client.tableDDL(statement);
   result = await client.forCompletion(result);
   console.log('Index nameIdx created');
} catch(error){
  //handle errors 
}
子表の作成: APIクラスおよびメソッドを使用して、DDL文を実行して子表を作成します。子表の作成時に、子表が親表の制限を継承するため、表の制限を明示的に設定する必要はありません。
/**
  * This function will create the child table userDetails with two columns,
  * one string column address which will be the primary key and one integer column 
  * which will be the salary.
  * @param {NoSQLClient} handle An instance of NoSQLClient
  */
const TABLE_NAME = 'users';
const CHILDTABLE_NAME = 'userDetails';
async function createChildTable(handle) {
    const createChildtblDDL = `CREATE TABLE IF NOT EXISTS ${TABLE_NAME}.${CHILDTABLE_NAME}
   (address STRING, salary INTEGER, PRIMARY KEY(address))`;
    console.log('Create table: ' + createChildtblDDL);
    let res =  await handle.tableDDL(createChildtblDDL, {complete: true});
}

表の一覧を検索します:

表の一覧を取得できます。
let varListTablesResult = await client.listTables();
console.log("The tables in the given compartment are:")
{res.send(varListTablesResult)}
表のスキーマもいつでもフェッチできます。
let resExistingTab = await client.getTable(tablename);
{ await client.forCompletion(resExistingTab);}
console.log("The  schema details for the table is:")
{ res.send(resExistingTab.schema)}

表を作成し、他のデータ定義言語(DDL)文(表の作成、変更および削除、索引の作成および削除など)を実行するには、ExecuteTableDDLAsyncおよびExecuteTableDDLWithCompletionAsyncメソッドを使用します。メソッドExecuteTableDDLAsyncおよびExecuteTableDDLWithCompletionAsyncは、Task<TableResult>を返します。TableResultインスタンスには、TableStateや表スキーマなどのDDL操作のステータスが含まれます。これらの各メソッドには、複数のオーバーロードがあります。特に、DDL操作のオプションをTableDDLOptionsとして渡すことができます。

これらは長時間実行される可能性があることに注意してください。メソッドExecuteTableDDLAsyncは、サービスによって指定されたDDL操作のみを起動し、その完了を待機しません。返されるTableResultインスタンスでWaitForCompletionAsyncをコールすることで、表DDL操作の完了を非同期で待機できます。
var client = new NoSQLClient("config.json");
try { 
  var statement = "CREATE TABLE IF NOT EXISTS users(id INTEGER,"
    + "name STRING, PRIMARY KEY(id))";

var result = await client.ExecuteTableDDLAsync(statement);
  await result.WaitForCompletionAsync(); 
  Console.WriteLine("Table users created."); 
} catch(Exception ex) {
   // handle exceptions
}
WaitForCompletionAsyncは、操作の完了を反映するようにコール元のTableResultインスタンスを変更することに注意してください。
または、ExecuteTableDDLWithCompletionAsyncを使用することもできます。try-catchブロックの文を次のように置き換えます。
var statement = "CREATE TABLE IF NOT EXISTS users(id INTEGER,"
    + "name STRING, PRIMARY KEY(id))"; 


await client.ExecuteTableDDLWithCompletionAsync(statement);
Console.WriteLine("Table users created.");
子表の作成: APIクラスおよびメソッドを使用して、DDL文を実行して子表を作成します。子表の作成時に、子表が親表の制限を継承するため、表の制限を明示的に設定する必要はありません。
private const string TableName = "users";
private const string ChildTableName = "userDetails";
// Create a child table
var childtblsql = $"CREATE TABLE IF NOT EXISTS {TableName}.{ChildTableName}
address STRING, salary INTEGER, PRIMARY KEY(address))";
Console.WriteLine("\nCreate table {0}", ChildTableName);
var tableResult = await client.ExecuteTableDDLAsync(childtblsql);
Console.WriteLine("  Creating table {0}", ChildTableName);
Console.WriteLine("  Table state: {0}", tableResult.TableState);
// Wait for the operation completion
await tableResult.WaitForCompletionAsync();
Console.WriteLine("  Table {0} is created",tableResult.TableName);
Console.WriteLine("  Table state: {0}", tableResult.TableState);

表の一覧を検索します:

表の一覧を取得できます。
varresult = await client.ListTablesAsync(); 
console.WriteLine("The tables in the given compartment are:") 
foreach(var tableName inresult.TableNames){
   Console.WriteLine(tableName);
}

Springデータ・アプリケーションでは、@NosqlTable.autoCreateTablefalseに設定されていないかぎり、エンティティの初期化時に表がアプリケーションの開始時に自動的に作成されます。

永続化するUsersエンティティ・クラスを作成します。このエンティティ・クラスはOracle NoSQL Databaseの表を表しています。また、このエンティティのインスタンスはその表の行に対応します。

IDフィールドを示す@NosqlId注釈を指定します。generated=true属性は、IDが自動生成されることを指定します。表レベルのTTLを設定するには、エンティティ・クラスの@NosqlTable注釈にttl()およびttlUnit()パラメータを指定します。すべてのSpring Dataクラス、メソッド、インタフェースおよび例の詳細は、SDK for Spring Data APIリファレンスを参照してください。

IDフィールド・タイプが文字列の場合は、UUIDが使用されます。IDフィールド・タイプがintまたはlongの場合は、"GENERATED ALWAYS as IDENTITY (NO CYCLE)"シーケンスが使用されます。

import com.oracle.nosql.spring.data.core.mapping.NosqlId;
import com.oracle.nosql.spring.data.core.mapping.NosqlTable;
/* The @NosqlTable annotation specifies that this class will be mapped to an Oracle NoSQL Database table. */
/* Sets the table level TTL to 10 Days. */
@NosqlTable(ttl = 10, ttlUnit = NosqlTable.TtlUnit.DAYS)

public class Users {
    @NosqlId(generated = true)
    long id;
    String firstName;
    String lastName;
 
    /* public or package-protected constructor is required when retrieving from the database. */
    public Users() {
    }
 
    @Override
    public String toString() {
        return "Users{" +
                "id=" + id + ", " +
                "firstName=" + firstName + ", " +
                "lastName=" + lastName +
                '}';
    }
}
次のUsersRepositoryインタフェースを作成します。このインタフェースは、NosqlRepositoryインタフェースを拡張して、そのクラスの主キーのエンティティ・クラスとデータ型をパラメータ化された型としてNosqlRepositoryインタフェースに提供します。このNosqlRepositoryインタフェースは、データベースのデータの格納または取得に使用されるメソッドを備えています。
import com.oracle.nosql.spring.data.repository.NosqlRepository;
 
/* The Users is the entity class and Long is the data type of the primary key in the Users class.
   This interface provides methods that return iterable instances of  the Users class. */
 
public interface UsersRepository extends NosqlRepository<Users, Long> {
    /* Search the Users table by the last name and return an iterable instance of the Users class.*/
    Iterable<Users> findByLastName(String lastname);
}
SpringのCommandLineRunnerインタフェースを使用して、runメソッドを実装し、mainメソッドを持つアプリケーション・コードを表示できます。

ノート:

Spring Data Frameworkが提供する各種インタフェースのいずれかを実装することで、目的の要件に応じた機能をコーディングできます。Spring bootアプリケーションの設定の詳細は、「Spring Boot」を参照してください。
import com.oracle.nosql.spring.data.core.NosqlTemplate;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
 
/* The @SpringBootApplication annotation helps you to build an application using Spring Data Framework rapidly.*/
@SpringBootApplication
public class App implements CommandLineRunner {
 
    /* The annotation enables Spring Data Framework to look up the configuration file for a matching bean.*/
    @Autowired
    private UsersRepository repo;
 
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx =
                SpringApplication.run(App.class, args);
        SpringApplication.exit(ctx, () -> 0);
        ctx.close();
        System.exit(0);
    }
 
    @Override
    public void run(String... args) throws Exception {
    }
}
Spring Dataアプリケーションを使用して表を作成すると、スキーマが自動的に作成され、主キー列(文字列、int、longまたはtimestamp型)とkv_json_というJSON列という2つの列が含まれます。

ノート:

表がすでに存在する場合は、生成されたスキーマに準拠する必要があります。

Users表のフィールドに索引を作成するには、NosqlTemplate.runTableRequest()を使用します。

Oracle NoSQL Databaseの接続詳細を指定するために、AbstractNosqlConfigurationクラスを拡張するAppConfigクラスを作成します。詳細は、「NoSQL接続の取得」を参照してください。

アプリケーションでは、AppConfigクラスのインスタンスにNosqlTemplate create (NosqlDbConfig nosqlDBConfig)メソッドを指定して、NosqlTemplateクラスをインスタンス化します。次に、NosqlTemplate.runTableRequest()メソッドを使用して表を変更します。NosqlTemplate.runTableRequest()メソッドで索引を作成するためのNoSQL文を指定します。

この例では、Users表のlastNameフィールドに索引を作成します。
import com.oracle.nosql.spring.data.core.NosqlTemplate;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
 
/* Create an Index on the lastName field of the Users Table. */
 
try {
    AppConfig config = new AppConfig();
    NosqlTemplate idx = NosqlTemplate.create(config.nosqlDbConfig());
    idx.runTableRequest("CREATE INDEX IF NOT EXISTS nameIdx ON Users(kv_json_.lastName AS STRING)");
    System.out.println("Index created successfully");
} catch (Exception e) {
    System.out.println("Exception creating index" + e);
}

表の作成の詳細は、Spring Data SDK開発者ガイド例: Spring Data Frameworkを使用したOracle NoSQL Databaseへのアクセスを参照してください。