Using APIs to Create Tables and Indexes in Oracle NoSQL Database Cloud Service

Learn how to create tables and indexes from your Java, Python, Go, Node.js, or .NET application.

This article has the following topics:

About Oracle NoSQL Database SDK drivers

Learn about Oracle NoSQL Database SDK drivers.

The Oracle NoSQL Database SDK Driver contains the files that enable an application to communicate with the on-premises or the Oracle NoSQL Database Cloud Service or the Oracle NoSQL Database Cloud Simulator.

The Oracle NoSQL Database SDK for Java is available in Maven Central repository, details available here. The main location of the project is in GitHub.

You can get all the required files for running the SDK with the following POM file dependencies.

Note:

The version changes with each release.
<dependency>
  <groupId>com.oracle.nosql.sdk</groupId>
  <artifactId>nosqldriver</artifactId>
  <version>5.2.31</version>
</dependency>

The Oracle NoSQL Database SDK for Java provides you with all the Java classes, methods, interfaces and examples. Documentation is available as javadoc in GitHub or from Java API Reference Guide.

You can install the Python SDK through the Python Package Index with the command given below.

pip3 install borneo

The Oracle NoSQL SDK for Python provides you with all the Python classes, methods, interfaces and examples. Documentation is available in Python API Reference Guide.

Open the Go Downloads page in a browser and click the download tab corresponding to your operating system. Save the file to your home folder.

Install Go in your operating system.
  • On Windows systems, Open the MSI file you downloaded and follow the prompts to install Go.
  • On Linux systems, Extract the archive you downloaded into /usr/local, creating a Go tree in /usr/local/go. Add /usr/local/go/bin to the PATH environment variable.

Access the online godoc for information on using the SDK and to reference Go driver packages, types, and methods.

Download and install Node.js 12.0.0 or higher version from Node.js Downloads. Ensure that Node Package Manager (npm) is installed along with Node.js. Install the node SDK for Oracle NoSQL Database as shown below.
npm install oracle-nosqldb

Access the Node.js API Reference Guide to reference Node.js classes, events, and global objects.

You can install the SDK from NuGet Package Manager either by adding it as a reference to your project or independently.
  • Add the SDK as a Project Reference: You may add the SDK NuGet Package as a reference to your project by using .Net CLI.
    cd <your-project-directory>
    dotnet add package Oracle.NoSQL.SDK
    Alternatively, you may perform the same using NuGet Package Manager in Visual Studio.
  • Independent Install: You may install the SDK independently into a directory of your choice by using nuget.exe CLI.
    nuget.exe install Oracle.NoSQL.SDK -OutputDirectory
    <your-packages-directory>

Obtaining a NoSQL Handle

Learn how to access tables using Oracle NoSQL Database Drivers. Start developing your application by creating a NoSQL Handle. Use the NoSQLHandle to access the tables and execute all operations.

To create a connection represented by a NoSQLHandle, obtain a handle using the NoSQLHandleFactory.createNoSQLHandle method and the NoSQLHandleConfig class. The NoSQLHandleConfig class allows an application to specify the handle configuration. See the Java API Reference Guide to learn more.

Use the following code to obtain a NoSQL handle:
/* Configure a handle for the desired Region and AuthorizationProvider.
 * By default this SignatureProvider constructor reads authorization
 * information from ~/.oci/config and uses the default user profile and
 * private key for request signing. Additional SignatureProvider
 * constructors are available if a config file is not available or
 * desirable. 
 */
AuthorizationProvider ap = new SignatureProvider();

/* Use the us-ashburn-1 region */
NoSQLHandleConfig config = new NoSQLHandleConfig(Region.US_ASHBURN_1, ap);
config.setAuthorizationProvider(ap);

/* Sets a default compartment for all requests from this handle. This 
 * may be overridden in individual requests or by using a
 * compartment-name prefixed table name.
 */
config.setDefaultCompartment("mycompartment");

// Open the handle
NoSQLHandle handle = NoSQLHandleFactory.createNoSQLHandle(config);

// Use the handle to execute operations

A handle has memory and network resources associated with it. Use the NoSQLHandle.close method to free up the resources when your application is done using the handle.

To minimize network activity and resource allocation and deallocation overheads, it's best to avoid creating and closing handles repeatedly. For example, creating and closing a handle around each operation would result in poor application performance. A handle permits concurrent operations, so a single handle is sufficient to access tables in a multi-threaded application. The creation of multiple handles incurs additional resource overheads without providing any performance benefit.

A handle is created by first creating a borneo.NoSQLHandleConfig instance to configure the communication endpoint, authorization information, as well as default values for handle configuration. borneo.NoSQLHandleConfig represents a connection to the service. Once created it must be closed using the method borneo.NoSQLHandle.close() in order to clean up resources. Handles are thread-safe and intended to be shared.

An example of acquiring a NoSQL Handle for the Oracle NoSQL Cloud Service:
from borneo import NoSQLHandle, NoSQLHandleConfig, Regions
from borneo.iam import SignatureProvider
# create AuthorizationProvider
provider = SignatureProvider()
# create handle config using the correct desired region
# as endpoint, add a default compartment.
config = NoSQLHandleConfig(Regions.US_ASHBURN_1).
set_authorization_provider(provider).
set_default_compartment('mycompartment')
# create the handle
handle = NoSQLHandle(config)

Note:

To reduce resource usage and overhead of handle creation it is best to avoid excessive creation and closing of borneo.NoSQLHandle instances.
The first step in any Oracle NoSQL Database Cloud Service go application is to create a nosqldb.Client handle used to send requests to the service. Instances of the Client handle are safe for concurrent use by multiple goroutines and intended to be shared in a multi-goroutines application. The handle is configured using your credentials and other authentication information.
provider, err := iam.NewSignatureProviderFromFile(cfgfile, profile, passphrase, compartment)
cfg := nosqldb.Config
{ 
   Region: "us-phoenix-1", AuthorizationProvider: provider,
}
client, err := nosqldb.NewClient(cfg)
// use client for all NoSQL DB operations

Class NoSQLClient represents the main access point to the service. To create instance of NoSQLClient you need to provide appropriate configuration information. This information is represented by a plain JavaScript object and may be provided to the constructor of NoSQLClient as the object literal. Alternatively, you may choose to store this information in a JSON configuration file and the constructor of NoSQLClient with the path (absolute or relative to the application's current directory) to that file.

The first example below creates instance of NoSQLClient for the Cloud Service using configuration object literal. It also adds a default compartment and overrides some default timeout values in the configuration object.
const NoSQLClient = require('oracle-nosqldb').NoSQLClient;

let client = new NoSQLClient({
    region: Region.US_ASHBURN_1,
    timeout: 20000,
    ddlTimeout: 40000,
    compartment: 'mycompartment',
    auth: {
        iam: {
            configFile: '~/myapp/.oci/config',
            profileName: 'Jane'
        }
    }
});

The second example stores the same configuration in a JSON file config.json and uses it to create NoSQLClient instance.

Sample config.json file:
{ 
"region": "US_ASHBURN_1",
 "timeout": 20000,
 "ddlTimeout": 40000,
 "compartment": "mycompartment", 
 "auth": { 
    "iam": { 
       "configFile": "~/myapp/.oci/config",
       "profileName": "Jane"
    } 
  }
}
Application code:
const NoSQLClient = require('oracle-nosqldb').NoSQLClient;
let client = new NoSQLClient('config.json');

Class NoSQLClient represents the main access point to the service. To create an instance of NoSQLClient you need to provide appropriate configuration information. This information is represented by NoSQLConfig class which instance can be provided to the constructor of NoSQLClient. Alternatively, you may choose to store the configuration information in a JSON configuration file and use the constructor of NoSQLClient that takes the path (absolute or relative to current directory) to that file.

The first example below creates instance of NoSQLClient for the Cloud Service using NoSQLConfig. It also adds a default compartment and overrides some default timeout values in NoSQLConfig.
var client = new NoSQLClient(
    new NoSQLConfig
    {
        Region = Region.US_ASHBURN_1,
        Timeout = TimeSpan.FromSeconds(10),
        TableDDLTimeout = TimeSpan.FromSeconds(20),
        Compartment = "mycompartment",
        AuthorizationProvider = new IAMAuthorizationProvider(
            "~/myapp/.oci/config", "Jane")
    });

The second example stores the same configuration in a JSON file config.json and uses it to create NoSQLClient instance.

config.json
{
    "Region": "us-ashburn-1",
    "Timeout": 20000,
    "TableDDLTimeout": 40000,
    "compartment": "mycompartment",
    "AuthorizationProvider":
    {
        "AuthorizationType": "IAM",
        "ConfigFile": "~/myapp/.oci/config",
        "ProfileName": "Jane"
    }
}
Application code:
var client = new NoSQLClient("config.json");

About Compartments

Learn how to specify the compartment while creating and working with Oracle NoSQL Database Cloud Service tables using Oracle NoSQL Database Drivers.

Oracle NoSQL Database Cloud Service tables are created in a compartment and are scoped to that compartment. When authenticated as a specific user, your tables are managed in the root compartment of your tenancy unless otherwise specified. Organizing tables into different compartments will help with respect to organization and security.

If you have been authenticated using an instance principal (accessing the service from an OCI compute instance), you must specify a compartment using its id (OCID), as there is no default in this case. See Calling Service From an Instance in Oracle Cloud Infrastructure Documentation.

There are several ways to specify a compartment in your application code:
  1. Use a default compartment in NoSQLHandleConfig so that it applies to all the operations using the handle. See Obtaining a NoSQL Handle for an example.
  2. Use the compartment name or id (OCID) in each request in addition to the table name. This overrides any default compartment.
    For example:
    GetRequest getReq = new GetRequest().setTableName("mytable")
                                        .setCompartment("mycompartment");
  3. Use the compartment name as a prefix on the table name. This overrides any default compartment as well as a compartment specified using API.
    For example:
    GetRequest getReq = new GetRequest().setTableName("mycompartment:mytable");
When using a named compartment, the name can be the simple name of a top-level compartment or a path to a nested compartment. In the latter case, the path is a "." (dot) separated path.

Note:

While specifying the path to a nested compartment, do not include the top-level compartment's name in the path as that is inferred from the tenancy.
There are several ways to specify a compartment in your application code:
  • A method exists to allow specification of a default compartment for requests in borneo.NoSQLHandleConfig.set_compartment(). This overrides the user’s default compartment.
  • In addition, it is possible to specify a compartment in each Request instance.
The set_compartment methods take either an id (OCID) or a compartment name or a path. If a compartment name is used it may be the name of a top-level compartment.

Note:

If a compartment path is used to reference a nested compartment, the path is a dot-separate path that excludes the top-level compartment of the path, for example, compartmentA.compartmentB.
Instead of setting a compartment in the request, it is possible to use a compartment name to prefix a table name in a request, query, or DDL statement. This usage overrides any other setting of the compartment. For example,
...
request = PutRequest().set_table_name('mycompartment:mytable')
...
create_statement = 'create table mycompartment:mytable(...)' 
...
request = GetRequest().set_table_name('compartmentA.compartmentB')
There are several ways to specify a compartment in your application code:
  • You can set a desired compartment name or id.
  • Set to an empty string to use the default compartment, that is the root compartment of the tenancy.
  • If using a nested compartment, specify the full compartment path relative to the root compartment as compartmentID. For example, if using rootCompartment.compartmentA.compartmentB, the compartmentID should be set to compartmentA.compartmentB.
  • You can also use the compartment OCID as the string value.
compartmentID:="<optional-compartment-name-or-ID>"
iam.NewRawSignatureProvider(tenancy, user, region, fingerprint, compartmentID,
        privateKey, &privateKeyPassphrase)
The default compartment for tables is the root compartment of the user's tenancy. A default compartment for all operations can be specified by setting the Compartment property of NoSQLConfig. For example:
const NoSQLClient = require('oracle-nosqldb').NoSQLClient;
const client = new NoSQLClient({
    region: Region.US_ASHBURN_1,
    compartment: 'mycompartment'
});

The string value may be either a compartment id or a compartment name or path. If it is a simple name it must specify a top-level compartment. If it is a path to a nested compartment, the top-level compartment must be excluded as it is inferred from the tenancy. A compartment can also be specified in each request in the options object. This value overrides the initial configuration value.

If compartment is not supplied, the tenancy OCID will be used as default. Note this only applies if you are authorizing with user's identity. When using instance principal or resource principal, compartment id must be specified.

The default compartment for tables is the root compartment of the user's tenancy. A default compartment for all operations can be specified by setting the Compartment property of NoSQLConfig. For example:
var client = new NoSQLClient(
    new NoSQLConfig
    {
        Region=Region.US_ASHBURN_1,
        Compartment="<compartment_ocid_or_name>"
    });
The string value may be either a compartment OCID or a compartment name or path. If it is a simple name it must specify a top-level compartment. If it is a path to a nested compartment, the top-level compartment must be excluded as it is inferred from the tenancy.

In addition, all operation options classes have Compartment property, such as TableDDLOptions.Compartment, GetOptions.Compartment, PutOptions.Compartment, etc. Thus you may also specify comparment separately for any operation. This value, if set, will override the compartment value in NoSQLConfig, if any.

If compartment is not supplied, the tenancy OCID will be used as default. Note this only applies if you are authorizing with user's identity. When using instance principal or resource principal, compartment id must be specified.

Creating Tables and Indexes

Learn how to create tables and indexes.

Creating a table is the first step of developing your application.

You use the API class and methods to execute all DDL statements, such as, creating, modifying, and dropping tables. You can also set table limits using the API method.

Examples of DDL statements are:

/* 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 index called nameIdx on the name field in the users table */
CREATE INDEX IF NOT EXISTS nameIdx ON users(name)

The following example considers that the default compartment is specified in NoSQLHandleConfig while obtaining the NoSQL handle. See Obtaining a NoSQL Handle . To explore other options of specifying a compartment for the NoSQL tables, see About Compartments .

Create a table and index using the TableRequest and its methods.

/* 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";
/* Call the appropriate constructor for 
 * 1) Provisioned Capacity
 * TableLimits limits = new TableLimits(50, 50, 25);
 * 2) On-demand Capacity - only set storage limit
 * TableLimits limits = new TableLimits( 5 );   
 * In this example, we will use Provisioned Capacity 
*/
TableLimits limits = new TableLimits(50, 50, 25);
TableRequest treq = new TableRequest().setStatement(createTableDDL)
 .setTableLimits(limits);

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

// wait for completion of the operation
tres.waitForCompletion(handle,
 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);

// wait for completion of the operation
  tres.waitForCompletion(handle,
   60000, // wait for 60 sec
   1000); // delay in ms for poll
DDL statements are executed using the borneo.TableRequest class. All calls to borneo.NoSQLHandle.table_request() are asynchronous so it is necessary to check the result and call borneo.TableResult.wait_for_completion() to wait for the operation to complete.
#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'
# In the Cloud Service TableLimits is a required object for table 
#creation. It specifies the throughput and capacity for the table in 
#ReadUnits,  WriteUnits, GB
# Call the appropriate constructor for 
# 1) Provisioned Capacity
# TableLimits(50, 50, 25);
#  2) On-demand Capacity - only set storage limit
# TableLimits( 25 );  
# In this example, we will use Provisioned Capacity 
request = TableRequest().set_statement(statement).
                        set_table_limits( TableLimits(50, 50, 25))
# 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)
The following example creates a simple table with an integer key and a single STRING field. The create table request is asynchronous. You wait for the table creation to complete.
// 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)
// Call the appropriate constructor for
// 1) Provisioned Capacity
// &nosqldb.TableLimits(ReadUnits: 50, WriteUnits: 50, StorageGB: 25);
// 2) On-demand Capacity - only set storage limit
// &nosqldb.TableLimits(StorageGB: 25 );   
// In this example, we will use Provisioned Capacity
tableReq := &nosqldb.TableRequest{
    Statement: stmt,
    TableLimits: &nosqldb.TableLimits{
        ReadUnits:  50,
        WriteUnits: 50,
        StorageGB:  25,
    },
}
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 ")

Table DDL statements are executed by tableDDL method. Like most other methods of NoSQLClient class, this method is asynchronous and it returns a Promise of TableResult. TableResult is a plain JavaScript object that contains status of DDL operation such as its TableState, name, schema and its TableLimit.

tableDDL method takes opt object as the 2nd optional argument. When you are creating a table, you must specify its TableLimits as part of the opt argument. TableLimits specifies maximum throughput and storage capacity for the table as the amount of read units, write units, and Gigabytes of storage.

Note that tableDDL method only launches the specified DDL operation in the underlying store and does not wait for its completion. The resulting TableResult will most likely have one of intermediate table states such as TableState.CREATING, TableState.DROPPING or TableState.UPDATING (the latter happens when table is in the process of being altered by ALTER TABLE statement, table limits are being changed or one of its indexes is being created or dropped).

When the underlying operation completes, the table state should change to TableState.ACTIVE or TableState.DROPPED (the latter if the DDL operation was 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))';
// Call the appropriate constructor for
// 1) Provisioned Capacity
//  tableLimits: {readUnits: 50, writeUnits: 50, storageGB: 25);
// 2) On-demand Capacity - only set storage limit
//  tableLimits: {storageGB: 25 );   
// In this example, we will use Provisioned Capacity
        let result = await client.tableDDL(statement, {
            tableLimits: {
                readUnits: 50,
                writeUnits: 50,
                storageGB: 25
            }
        });
        result = await client.forCompletion(result);
        console.log('Table users created');
    } catch(error) {
        //handle errors
    }
}
After the above call returns, result will reflect final state of the operation. Alternatively, to use complete option, substitute the code in try-catch block above with the following:
const statement = 'CREATE TABLE IF NOT EXISTS users(id INTEGER, ' +
        'name STRING, PRIMARY KEY(id))';
// Call the appropriate constructor for
// 1) Provisioned Capacity
//  tableLimits: {readUnits: 50, writeUnits: 50, storageGB: 25);
// 2) On-demand Capacity - only set storage limit
//  tableLimits: {storageGB: 25 );   
// In this example, we will use Provisioned Capacity
    let result = await client.tableDDL(statement, {
        tableLimits: {
            readUnits: 50,
            writeUnits: 50,
            storageGB: 25
        },
        complete: true
    });
    console.log('Table users created');

You need not specify TableLimits for any DDL operation other than CREATE TABLE. You may also change table limits of the table after it has been created by calling setTableLimits method. This may also require waiting for the completion the operation in the same way as waiting for completion of operations initiated by tableDDL.

// 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 
}

To create tables and execute other Data Definition Language (DDL) statements, such as creating, modifying and dropping tables as well as creating and dropping indexes, use methods ExecuteTableDDLAsync and ExecuteTableDDLWithCompletionAsync. Methods ExecuteTableDDLAsync and ExecuteTableDDLWithCompletionAsync return Task<TableResult>. TableResult instance contains status of DDL operation such as TableState, table schema and TableLimits. Each of these methods comes with several overloads. In particular, you may pass options for the DDL operation as TableDDLOptions.

When creating a table, you must specify its TableLimits. Table limits specify maximum throughput and storage capacity for the table as the amount of read units, write units and Gigabytes of storage. You may use an overload that takes tableLimits parameter or pass table limits as TableLimits property of TableDDLOptions. Note that these are potentially long running operations. The method ExecuteTableDDLAsync only launches the specified DDL operation by the service and does not wait for its completion. You may asynchronously wait for table DDL operation completion by calling WaitForCompletionAsync on the returned TableResult instance.
var client = new NoSQLClient("config.json");
try { 
  var statement = "CREATE TABLE IF NOT EXISTS users(id INTEGER,"
    + "name STRING, PRIMARY KEY(id))";
// Call the appropriate constructor for
// 1) Provisioned Capacity
// new TableLimits(50, 50, 25);
// 2) On-demand Capacity - only set storage limit
// new TableLimits( 25 );   
// In this example, we will use Provisioned Capacity
  var result = await client.ExecuteTableDDLAsync(statement, new
    TableLimits(50, 50, 25)); 
  await result.WaitForCompletionAsync(); 
  Console.WriteLine("Table users created."); 
} catch(Exception ex) {
   // handle exceptions
}
Note that WaitForCompletionAsync will change the calling TableResult instance to reflect the operation completion.
Alternatively you may use ExecuteTableDDLWithCompletionAsync. Substitute the statements in the try-catch block with the following:
var statement = "CREATE TABLE IF NOT EXISTS users(id INTEGER,"
    + "name STRING, PRIMARY KEY(id))"; 
// Call the appropriate constructor for
// 1) Provisioned Capacity
// new TableLimits(50, 50, 25);
// 2) On-demand Capacity - only set storage limit
// new TableLimits(25 );   
// In this example, we will use Provisioned Capacity
await client.ExecuteTableDDLWithCompletionAsync(statement, 
       new  TableLimits(50, 50, 25)); 
Console.WriteLine("Table users created.");
You need not specify TableLimits for any DDL operation other than CREATE TABLE. You may also change table limits of an existing table by calling SetTableLimitsAsync or SetTableLimitsWithCompletionAsync methods.

Related Topics