Class Table<WSchema, PKey, RSchema>

Overview

Represents the interface to a table in a Data-API-enabled database.

This shouldn't be directly instantiated, but rather created via Db.createTable or Db.table.

Example

// Basic creation of a dynamically typed table
// (If you don't provide `SomeRow` explicitly, it will
// attempt to infer the Table's type from the definition)
const table = await db.createTable<SomeRow>('users', {
  definition: {
  columns: {
  id: 'text',
  name: 'text',
  },
  primaryKey: 'id',
  },
});

// or (also dynamically typed)
const table = db.table('users');

Typing & Types

NOTE: For most intents & purposes (unless you're using custom ser/des), you can ignore the (generally negligible) difference between WSchema and RSchema, and treat Table as if it were typed as Table<Schema, PKey>.

A Table is typed as Table<WSchema, PKey, RSchema>, where:

  • WSchema is the type of the row as it's written to the table (the "write" schema)
    • This includes inserts, filters, sorts, etc.
  • PKey (optional) is the type of the primary key of the table as it's returned
  • RSchema is the type of the row as it's read from the table (the "read" schema)
    • This includes finds
    • Unless custom ser/des is used, it is nearly exactly the same as WSchema
    • It defaults to FoundRow<WSchema> (see FoundRow)

See FoundRow for more info about the differences, but again, for most intents & purposes, you can ignore this, and pretend they were

Custom datatypes

Certain datatypes may be represented as TypeScript classes (some native, some provided by astra-db-ts), however.

For example:

  • 'map<k, v>' is represented by a native JS Map<K, V>
  • 'vector' is represented by an astra-db-ts provided DataAPIVector
  • 'date' is represented by an astra-db-ts provided DataAPIDate

You may also provide your own datatypes by providing some custom serialization logic as well (see later section).

Example

interface User {
  id: string,
  friends: Map<string, UUID>, // UUID is also `astra-db-ts` provided
  vector: DataAPIVector,
}

await db.table<User>('users').insertOne({
  id: '123',
  friends: new Map([['Alice', uuid(4)]]), // or UUID.v4()
  vector: vector([1, 2, 3]), // or new DataAPIVector([...])
});
Big numbers disclaimer

When varints or decimals are present in the schema, and when you're serializing bigints and BigNumbers, it will automatically enable usage of a bignumber-friendly JSON library which is capable of serializing/deserializing these numbers without loss of precision, but is much slower than the native JSON library (but, realistically, the difference is likely negligible).

Typing the key

The primary key of the table should be provided as a second type parameter to Table.

This is a special type that is used to reconstruct the TS type of the primary key in insert operations. It should be an object with the same keys as the primary key columns, and the same types as the schema. Note that there is no distinction between partition and clustering keys in this type.

Example

interface User {
  id: string, // Partition key
  dob: DataAPIDate, // Clustering (partition sort) key
  friends: Map<string, UUID>,
}

type UserPK = Pick<User, 'id' | 'dob'>;

// res.insertedId is of type { id: string }
const res = await db.table<User, UserPK>('users').insertOne({
  id: '123',
  dob: date(), // or new DataAPIDate(new Date())
  friends: new Map([['Alice', uuid(4)]]), // or UUID.v4()
});
db.createTable type inference

When creating a table through Db.createTable, and not using any custom datatypes (see next session), you can actually use the InferTableSchema & InferTablePrimaryKey utility types to infer the schema of the table from the table creation.

Example

// equivalent to:
// type User = {
// id: string,
// dob: DataAPIDate,
// friends?: Map<string, UUID>, // Optional since it's not in the primary key
// }
type User = InferTableSchema<typeof mkTable>;

// equivalent to:
// type UserPK = Pick<User, 'id' | 'dob'>;
type UserPK = InferTablePrimaryKey<typeof mkTable>;

const mkTable = () => db.createTable('users', {
  definition: {
  columns: {
  id: 'text',
  dob: 'date',
  friends: { type: 'map', keyType: 'text', valueType: 'uuid' },
  },
  primaryKey: {
  partitionBy: ['id'],
  partitionSort: { dob: -1 }
  },
  },
});

async function main() {
  const table: Table<User, UserPK> = await mkTable();
  // ... use table
}
Custom datatypes

You can plug in your own custom datatypes, as well as enable many other features by providing some custom serialization/deserialization logic through the serdes option in TableOptions, DbOptions, and/or DataAPIClientOptions.dbOptions.

Note however that this is currently not entirely stable, and should be used with caution.

See the official DataStax documentation for more info.

Disclaimer

It is on the user to ensure that the TS type of the Table corresponds with the actual CQL table schema, in its TS-deserialized form. Incorrect or dynamic tying could lead to surprising behaviours and easily-preventable errors.

See Db.createTable, Db.table, and InferTableSchema for much more information about typing.

See

  • SomeRow
  • Db.createTable
  • Db.table
  • InferTableSchema
  • InferTablePrimaryKey
  • TableSerDesConfig
  • TableOptions

Type Parameters

Constructors

Properties

#commands: CommandImpls<PKey>
#db: Db
#httpClient: DataAPIHttpClient<"normal">
keyspace: string

The keyspace that the table resides in.

name: string

The name of the table. Unique per keyspace.

Accessors

  • get _httpClient(): DataAPIHttpClient<"normal">
  • Backdoor to the HTTP client for if it's absolutely necessary. Which it almost never (if even ever) is.

    Returns DataAPIHttpClient<"normal">

Methods

  • Overview

    Performs one of the four available table-alteration operations:

    • add (adds columns to the table)
    • drop (removes columns from the table)
    • addVectorize (enabled auto-embedding-generation on existing vector columns)
    • dropVectorize (disables vectorize on existing enabled columns)

    Type Parameters

    Parameters

    Returns Promise<Table<NewWSchema, PKey, NewRSchema>>

    The table with the new schema type.

    Example

    interface User {
    id: UUID,
    vector: DataAPIVector,
    }
    const table = db.table<User>('users');

    // Add a column to the table
    type NewUser = User & { name: string };

    const newTable = await table.alter<NewUser>({
    operation: {
    add: {
    columns: { name: 'text' },
    },
    },
    });

    // Drop a column from the table (resets it to how it was originally)
    const oldTable = await newTable.alter<User>({
    operation: {
    drop: {
    columns: ['name'],
    },
    },
    });
    On returning Table

    The alter operation returns the table itself, with the new schema type.

    It is heavily recommended to store the result of the alter operation in a new variable, as the old table will not have the new schema type.

    You should provide the exact new type of the schema, or it'll just default to SomeRow.

  • Overview

    Creates a secondary non-vector index on the table.

    The operation blocks until the index is created and ready to use.

    See Table.createVectorIndex for creating vector indexes.

    Text indexes

    text and ascii-based indexes have access to a few additional options:

    • caseSensitive (default: true)
      • Allows searches to be case-insensitive, if false
    • normalize (default: true)
      • Normalize Unicode characters and diacritics before indexing, if true
    • ascii (default: false)
      • Converts non-ASCII characters to their US-ASCII equivalent before indexing, if true

    Parameters

    Returns Promise<void>

    A promise which resolves once the index is created.

  • Creates an index on an existing vector column in the table.

    The operation blocks until the index is created and ready to use.

    See Table.createIndex for creating non-vector indexes.

    Parameters

    Returns Promise<void>

    A promise which resolves once the index is created.

  • Overview

    Get the table definition, i.e. it's columns and primary key definition.

    The method issues a request to the Data API each time it is invoked, without caching mechanisms; this ensures up-to-date information for usages such as real-time collection validation by the application.

    Parameters

    • Optional options: WithTimeout<"tableAdminTimeoutMs">

      The options for this operation.

    Returns Promise<ListTableDefinition>

    The definition of the table.

    Example

    const definition = await table.definition();
    console.log(definition.columns);
  • Overview

    Deletes many rows from the table.

    Parameters

    • filter: TableFilter<WSchema>

      A filter to select the row(s) to delete.

    • Optional timeout: WithTimeout<"generalMethodTimeoutMs">

      The timeout for this operation.

    Returns Promise<void>

    A promise which resolves once the operation is completed.

    Example

    await table.insertOne({ pk: 'abc', ck: 3 });
    await table.insertOne({ pk: 'abc', ck: 4 });
    await table.deleteMany({ pk: 'abc' });
    Filtering

    There are different forms of accepted filters:

    • Providing the full primary key to delete a single row
    • With some or all of the partitionSort columns not provided
      • The least significant of them can also use an inequality/range predicate
    • Using an empty filter to truncate the entire table
    On returning void

    The deleteMany operation, as returned from the Data API, is always { deletedCount: -1 }, regardless of how many things are actually matched/modified.

    In that sense, returning constantly that one type is isomorphic to just returning void, as both realistically contain the same amount of information (i.e. none)

  • Overview

    Deletes a single row from the table.

    Parameters

    • filter: TableFilter<WSchema>

      A filter to select the row to delete.

    • Optional timeout: WithTimeout<"generalMethodTimeoutMs">

      The timeout for this operation.

    Returns Promise<void>

    A promise which resolves once the operation is completed.

    Example

    await table.insertOne({ pk: 'abc', ck: 3 });
    await table.deleteOne({ pk: 'abc', ck: 3 });
    Filtering

    The filter must contain an exact primary key to delete just one row.

    Attempting to pass an empty filter, filtering by only part of the primary key, or filtering by a non-primary key column will result in an error.

    On returning void

    The deleteOne operation, as returned from the Data API, is always { deletedCount: -1 }, regardless of how many things are actually matched/modified.

    In that sense, returning constantly that one type is isomorphic to just returning void, as both realistically contain the same amount of information (i.e. none)

  • Overview

    Drops the table from the database, including all the rows it contains.

    Parameters

    • Optional options: Omit<DropTableOptions, "keyspace">

      The options for this operation.

    Returns Promise<void>

    A promise which resolves when the table has been dropped.

    Example

    const table = await db.table('my_table');
    await table.drop();
    Disclaimer

    Once the table is dropped, this object is still technically "usable", but any further operations on it will fail at the Data API level; thus, it's the user's responsibility to make sure that the table object is no longer used.

    Remarks

    Use with caution. Wear your safety goggles. Don't say I didn't warn you.

  • Overview

    Find rows in the table, optionally matching the provided filter.

    Parameters

    • filter: TableFilter<WSchema>

      A filter to select the rows to find. If not provided, all rows will be returned.

    • Optional options: GenericFindOptions & {
          projection?: undefined;
      }

      The options for this operation.

    Returns TableFindCursor<WithSim<RSchema>, WithSim<RSchema>>

    a FindCursor which can be iterated over.

    Example

    const cursor = await table.find({ name: 'John Doe' });
    const docs = await cursor.toArray();
    Projection

    This overload of Table.find is used for when no projection is provided, and it is safe to assume the returned rows are going to be of type Schema.

    If it can not be inferred that a projection is definitely not provided, the Schema is forced to be Partial<Schema> if the user does not provide their own, in order to prevent type errors and ensure the user is aware that the row may not be of the same type as Schema.

    Filtering

    The filter can contain a variety of operators & combinators to select the rows. See TableFilter for much more information.

    If the filter is empty, all rows in the table will be returned (up to any provided/implied limit).

    Find by vector search

    If the table has vector search enabled, you can find the most relevant rows by providing a vector in the sort option.

    Vector ANN searches cannot return more than a set number of rows, which, at the time of writing, is 1000 items.

    Example

    await table.insertMany([
      { name: 'John Doe', vector: [.12, .52, .32] },
      { name: 'Jane Doe', vector: [.32, .52, .12] },
      { name: 'Dane Joe', vector: [.52, .32, .12] },
    ]);

    const cursor = table.find({}, {
      sort: { vector: [.12, .52, .32] },
    });

    // Returns 'John Doe'
    console.log(await cursor.next());
    Sorting

    The sort option can be used to sort the rows returned by the cursor. See Sort for more information.

    The DataStax documentation site also contains further information on the available sort operators.

    If the sort option is not provided, there is no guarantee as to the order of the rows returned.

    When providing a non-vector sort, the Data API will return a smaller number of rows, set to 20 at the time of writing, and stop there. The returned rows are the top results across the whole table according to the requested criterion.

    Example

    await table.insertMany([
      { name: 'John Doe', age: 1, height: 168 },
      { name: 'John Doe', age: 2, height: 42 },
    ]);

    const cursor = table.find({}, {
      sort: { age: 1, height: -1 },
    });

    // Returns 'John Doe' (age 2, height 42), 'John Doe' (age 1, height 168)
    console.log(await cursor.toArray());
    Other options

    Other available options include skip, limit, includeSimilarity, and includeSortVector. See TableFindOptions and FindCursor for more information.

    If you prefer, you may also set these options using a fluent interface on the FindCursor itself.

    Example

    // cursor :: FindCursor<string>
    const cursor = table.find({})
      .sort({ vector: [.12, .52, .32] })
      .projection<{ name: string, age: number }>({ name: 1, age: 1 })
      .includeSimilarity(true)
      .map(doc => `${doc.name} (${doc.age})`);

    Remarks

    When not specifying sorting criteria at all (by vector or otherwise), the cursor can scroll through an arbitrary number of rows as the Data API and the client periodically exchange new chunks of rows.

    --

    It should be noted that the behavior of the cursor in the case rows have been added/removed after the find was started depends on database internals, and it is not guaranteed, nor excluded, that such "real-time" changes in the data would be picked up by the cursor.

  • Overview

    Find rows in the table, optionally matching the provided filter.

    Type Parameters

    Parameters

    Returns TableFindCursor<TRaw, TRaw>

    a FindCursor which can be iterated over.

    Example

    const cursor = await table.find({ name: 'John Doe' });
    const docs = await cursor.toArray();
    Projection

    This overload of Table.find is used for when a projection is provided (or at the very least, it can not be inferred that a projection is NOT provided).

    In this case, the user must provide an explicit projection type, or the type of the rows will be Partial<Schema>, to prevent type-mismatches when the schema is strictly provided.

    Example

    interface User {
    name: string,
    car: { make: string, model: string },
    }

    const table = db.table<User>('users');

    // Defaulting to `Partial<User>` when projection is not provided
    const cursor = await table.find({}, {
      projection: { car: 1 },
    });

    // next :: { car?: { make?: string, model?: string } }
    const next = await cursor.next();
    console.log(next.car?.make);

    // Explicitly providing the projection type
    const cursor = await table.find<Pick<User, 'car'>>({}, {
      projection: { car: 1 },
    });

    // next :: { car: { make: string, model: string } }
    const next = await cursor.next();
    console.log(next.car.make);

    // Projection existence can not be inferred
    function mkFind(projection?: Projection) {
      return table.find({}, { projection });
    }

    // next :: Partial<User>
    const next = await mkFind({ car: 1 }).next();
    console.log(next.car?.make);
    Filtering

    The filter can contain a variety of operators & combinators to select the rows. See TableFilter for much more information.

    If the filter is empty, all rows in the table will be returned (up to any provided/implied limit).

    Find by vector search

    If the table has vector search enabled, you can find the most relevant rows by providing a vector in the sort option.

    Vector ANN searches cannot return more than a set number of rows, which, at the time of writing, is 1000 items.

    Example

    await table.insertMany([
      { name: 'John Doe', vector: [.12, .52, .32] },
      { name: 'Jane Doe', vector: [.32, .52, .12] },
      { name: 'Dane Joe', vector: [.52, .32, .12] },
    ]);

    const cursor = table.find({}, {
      sort: { vector: [.12, .52, .32] },
    });

    // Returns 'John Doe'
    console.log(await cursor.next());
    Sorting

    The sort option can be used to sort the rows returned by the cursor. See Sort for more information.

    The DataStax documentation site also contains further information on the available sort operators.

    If the sort option is not provided, there is no guarantee as to the order of the rows returned.

    When providing a non-vector sort, the Data API will return a smaller number of rows, set to 20 at the time of writing, and stop there. The returned rows are the top results across the whole table according to the requested criterion.

    Example

    await table.insertMany([
      { name: 'John Doe', age: 1, height: 168 },
      { name: 'John Doe', age: 2, height: 42 },
    ]);

    const cursor = table.find({}, {
      sort: { age: 1, height: -1 },
    });

    // Returns 'John Doe' (age 2, height 42), 'John Doe' (age 1, height 168)
    console.log(await cursor.toArray());
    Other options

    Other available options include skip, limit, includeSimilarity, and includeSortVector. See TableFindOptions and FindCursor for more information.

    If you prefer, you may also set these options using a fluent interface on the FindCursor itself.

    Example

    // cursor :: FindCursor<string>
    const cursor = table.find({})
      .sort({ vector: [.12, .52, .32] })
      .projection<{ name: string, age: number }>({ name: 1, age: 1 })
      .includeSimilarity(true)
      .map(doc => `${doc.name} (${doc.age})`);

    Remarks

    When not specifying sorting criteria at all (by vector or otherwise), the cursor can scroll through an arbitrary number of rows as the Data API and the client periodically exchange new chunks of rows.

    --

    It should be noted that the behavior of the cursor in the case rows have been added/removed after the find was started depends on database internals, and it is not guaranteed, nor excluded, that such "real-time" changes in the data would be picked up by the cursor.

  • Overview

    Find a single row in the table, optionally matching the provided filter.

    Parameters

    • filter: TableFilter<WSchema>

      A filter to select the rows to find. If not provided, all rows will be returned.

    • Optional options: GenericFindOneOptions & {
          projection?: undefined;
      }

      The options for this operation.

    Returns Promise<null | WithSim<RSchema>>

    A row matching the criterion, or null if no such row exists.

    Example

    const doc = await table.findOne({ name: 'John Doe' });
    
    Projection

    This overload of Table.findOne is used for when no projection is provided, and it is safe to assume the returned row is going to be of type Schema.

    If it can not be inferred that a projection is definitely not provided, the Schema is forced to be Partial<Schema> if the user does not provide their own, in order to prevent type errors and ensure the user is aware that the row may not be of the same type as Schema.

    Filtering

    The filter can contain a variety of operators & combinators to select the row. See TableFilter for much more information.

    If the filter is empty, and no Sort is present, it's undefined as to which row is selected.

    Find by vector search

    If the table has vector search enabled, you can find the most relevant row by providing a vector in the sort option.

    Example

    await table.insertMany([
      { name: 'John Doe', vector: [.12, .52, .32] },
      { name: 'Jane Doe', vector: [.32, .52, .12] },
      { name: 'Dane Joe', vector: [.52, .32, .12] },
    ]);

    const doc = table.findOne({}, {
      sort: { vector: [.12, .52, .32] },
    });

    // 'John Doe'
    console.log(doc.name);
    Sorting

    The sort option can be used to pick the most relevant row. See Sort for more information.

    The DataStax documentation site also contains further information on the available sort operators.

    If the sort option is not provided, there is no guarantee as to which of the rows which matches the filter is returned.

    Example

    await table.insertMany([
      { name: 'John Doe', age: 1, height: 168 },
      { name: 'John Doe', age: 2, height: 42 },
    ]);

    const doc = table.findOne({}, {
      sort: { age: 1, height: -1 },
    });

    // 'John Doe' (age 2, height 42)
    console.log(doc.name);
    Other options

    Other available options include includeSimilarity. See TableFindOneOptions for more information.

    If you want to get skip or includeSortVector as well, use Table.find with a limit: 1 instead.

    Example

    const doc = await cursor.findOne({}, {
    sort: { vector: [.12, .52, .32] },
    includeSimilarity: true,
    });
  • Overview

    Find a single row in the table, optionally matching the provided filter.

    Type Parameters

    Parameters

    Returns Promise<null | TRaw>

    A row matching the criterion, or null if no such row exists.

    Example

    const doc = await table.findOne({ name: 'John Doe' });
    
    Projection

    This overload of Table.findOne is used for when a projection is provided (or at the very least, it can not be inferred that a projection is NOT provided).

    In this case, the user must provide an explicit projection type, or the type of the returned row will be as Partial<Schema>, to prevent type-mismatches when the schema is strictly provided.

    Example

    interface User {
    name: string,
    car: { make: string, model: string },
    }

    const table = db.table<User>('users');

    // Defaulting to `Partial<User>` when projection is not provided
    const doc = await table.findOne({}, {
      projection: { car: 1 },
    });

    // doc :: { car?: { make?: string, model?: string } }
    console.log(doc.car?.make);

    // Explicitly providing the projection type
    const doc = await table.findOne<Pick<User, 'car'>>({}, {
      projection: { car: 1 },
    });

    // doc :: { car: { make: string, model: string } }
    console.log(doc.car.make);

    // Projection existence can not be inferred
    function findOne(projection?: Projection) {
      return table.findOne({}, { projection });
    }

    // doc :: Partial<User>
    const doc = await findOne({ car: 1 }).next();
    console.log(doc.car?.make);
    Filtering

    The filter can contain a variety of operators & combinators to select the row. See TableFilter for much more information.

    If the filter is empty, and no Sort is present, it's undefined as to which row is selected.

    Find by vector search

    If the table has vector search enabled, you can find the most relevant row by providing a vector in the sort option.

    Example

    await table.insertMany([
      { name: 'John Doe', vector: [.12, .52, .32] },
      { name: 'Jane Doe', vector: [.32, .52, .12] },
      { name: 'Dane Joe', vector: [.52, .32, .12] },
    ]);

    const doc = table.findOne({}, {
      sort: { vector: [.12, .52, .32] },
    });

    // 'John Doe'
    console.log(doc.name);
    Sorting

    The sort option can be used to pick the most relevant row. See Sort for more information.

    The DataStax documentation site also contains further information on the available sort operators.

    If the sort option is not provided, there is no guarantee as to which of the rows which matches the filter is returned.

    Example

    await table.insertMany([
      { name: 'John Doe', age: 1, height: 168 },
      { name: 'John Doe', age: 2, height: 42 },
    ]);

    const doc = table.findOne({}, {
      sort: { age: 1, height: -1 },
    });

    // 'John Doe' (age 2, height 42)
    console.log(doc.name);
    Other options

    Other available options include includeSimilarity. See TableFindOneOptions for more information.

    If you want to get skip or includeSortVector as well, use Table.find with a limit: 1 instead.

    Example

    const doc = await cursor.findOne({}, {
    sort: { vector: [.12, .52, .32] },
    includeSimilarity: true,
    });
  • Overview

    Upserts many rows into the table.

    Parameters

    Returns Promise<TableInsertManyResult<PKey>>

    The primary keys of the inserted rows (and the count)

    Example

    import { uuid, vector, ... } from '@datastax/astra-db-ts';

    await table1.insertMany([
      { id: uuid(4), name: 'John Doe' }, // or UUID.v4()
      { id: uuid(7), name: 'Jane Doe' },
    ]);

    // Insert a row with a vector
    // DataAPIVector class enables faster ser/des
    await table2.insertMany([
      { name: 'bob', vector: vector([.12, .52, .32]) }, // or new DataAPIVector([...])
      { name: 'alice', vector: vector([.12, .52, .32]), tags: new Set(['cool']) },
    ], { ordered: true });
    Chunking

    NOTE: This function paginates the insertion of rows in chunks to avoid running into insertion limits. This means multiple requests may be made to the server.

    This operation is not necessarily atomic. Depending on the amount of inserted rows, and if it's ordered or not, it can keep running (in a blocking manner) for a macroscopic amount of time. In that case, new rows that are inserted from another concurrent process/application may be inserted during the execution of this method call, and if there are duplicate keys, it's not easy to predict which application will win the race.

    By default, it inserts rows in chunks of 50 at a time. You can fine-tune the parameter through the chunkSize option. Note that increasing chunk size won't necessarily increase performance depending on row size. Instead, increasing concurrency may help.

    You can set the concurrency option to control how many network requests are made in parallel on unordered insertions. Defaults to 8.

    Example

    const rows = Array.from({ length: 100 }, (_, i) => ({ id: i }));
    await table.insertMany(rows, { batchSize: 100 });
    Upsert behavior

    When inserting a row with a primary key that already exists, the new row will be merged with the existing row, with the new values taking precedence.

    If you want to delete old values, you must explicitly set them to null (not undefined).

    Example

    // Since insertion is ordered, the last unique value for each
    // primary key will be the one that remains in the table.
    await table.insertMany([
      { id: '123', col1: 'i exist' },
      { id: '123', col1: 'i am new' },
      { id: '123', col2: 'me2' },
    ], { ordered: true });

    await table.findOne({ id: '123' }); // { id: '123', col1: 'i am new', col2: 'me2' }

    // Since insertion is unordered, it can not be 100% guaranteed
    // which value will remain in the table for each primary key,
    // as concurrent insertions may occur.
    await table.insertMany([
      { id: '123', col1: null },
      { id: '123', col1: 'hi' },
    ]);

    // coll1 may technically be either 'hi' or null
    await table.findOne({ id: '123' }); // { id: '123', col1: ? }
    Ordered insertions

    You may set the ordered option to true to stop the operation after the first error; otherwise all rows may be parallelized and processed in arbitrary order, improving, perhaps vastly, performance.

    Setting the ordered operation disables any parallelization so insertions truly are stopped after the very first error.

    Setting ordered also guarantees the order of upsert behavior, as described above.

    The primary key

    The type of the primary key of the table is inferred from the second PKey type-param of the table.

    If not present, it defaults to Partial<RSchema> to keep the result type consistent.

    Example

    interface User {
      id: string,
      name: string,
      dob?: DataAPIDate,
    }

    type UserPKey = Pick<User, 'id'>;

    const table = db.table<User, UserPKey>('table');

    // res.insertedIds is of type { id: string }[]
    const res = await table.insertMany([
      { id: '123', thing: 'Sunrise' },
      { id: '456', thing: 'Miso soup' },
    ]);
    console.log(res.insertedIds[0].id); // '123'
    InsertManyError

    If some rows can't be inserted, (e.g. they have the wrong data type for a column or lack the primary key), the Data API validation check will fail for those entire specific requests containing the faulty rows.

    Depending on concurrency & the ordered parameter, some rows may still have been inserted.

    In such cases, the operation will throw a TableInsertManyError containing the partial result.

    If a thrown exception is not due to an insertion error, e.g. a 5xx error or network error, the operation will throw the underlying error.

    In case of an unordered request, if the error was a simple insertion error, the TableInsertManyError will be thrown after every row has been attempted to be inserted. If it was a 5xx or similar, the error will be thrown immediately.

    Throws

    TableInsertManyError - If the operation fails.

  • Overview

    Atomically upserts a single row into the table.

    Parameters

    • row: WSchema

      The row to insert.

    • Optional timeout: WithTimeout<"generalMethodTimeoutMs">

      The timeout for this operation.

    Returns Promise<TableInsertOneResult<PKey>>

    The primary key of the inserted row.

    Example

    import { UUID, vector, ... } from '@datastax/astra-db-ts';

    // Insert a row with a specific ID
    await table.insertOne({ id: 'text-id', name: 'John Doe' });
    await table.insertOne({ id: UUID.v7(), name: 'Dane Joe' }); // or uuid(7)

    // Insert a row with a vector
    // DataAPIVector class enables faster ser/des
    const vec = vector([.12, .52, .32]); // or new DataAPIVector([.12, .52, .32])
    await table.insertOne({ id: 1, name: 'Jane Doe', vector: vec });

    // or if vectorize (auto-embedding-generation) is enabled for the column
    await table.insertOne({ id: 1, name: 'Jane Doe', vector: "Hey there!" });
    Upsert behavior

    When inserting a row with a primary key that already exists, the new row will be merged with the existing row, with the new values taking precedence.

    If you want to delete old values, you must explicitly set them to null (not undefined).

    Example

    await table.insertOne({ id: '123', col1: 'i exist' });
    await table.findOne({ id: '123' }); // { id: '123', col1: 'i exist' }

    await table.insertOne({ id: '123', col1: 'i am new' });
    await table.findOne({ id: '123' }); // { id: '123', col1: 'i am new' }

    await table.insertOne({ id: '123', col2: 'me2' });
    await table.findOne({ id: '123' }); // { id: '123', col1: 'i am new', col2: 'me2' }

    await table.insertOne({ id: '123', col1: null });
    await table.findOne({ id: '123' }); // { id: '123', col2: 'me2' }
    The primary key

    The type of the primary key of the table is inferred from the second PKey type-param of the table.

    If not present, it defaults to Partial<RSchema> to keep the result type consistent.

    Example

    interface User {
      id: string,
      name: string,
      dob?: DataAPIDate,
    }

    type UserPKey = Pick<User, 'id'>;

    const table = db.table<User, UserPKey>('table');

    // res.insertedId is of type { id: string }
    const res = await table.insertOne({ id: '123', name: 'Alice' });
    console.log(res.insertedId.id); // '123'
  • Lists the index names for this table.

    If you want to include the index definitions in the response, set nameOnly to false (or omit it completely), using the other overload.

    Parameters

    • options: ListIndexOptions & {
          nameOnly: true;
      }

      Options for this operation.

    Returns Promise<string[]>

    A promise that resolves to an array of index names.

    Example

    // ['my_vector_index', ...]
    console.log(await table.listIndexes({ nameOnly: true }));
  • Lists the indexes for this table.

    If you want to use only the index names, set nameOnly to true, using the other overload.

    Parameters

    • Optional options: ListIndexOptions & {
          nameOnly?: false;
      }

      Options for this operation.

    Returns Promise<TableIndexDescriptor[]>

    A promise that resolves to an array of index info.

    Example

    // [{ name: 'm_vector_index', definition: { ... } }, ...]
    console.log(await db.listTables());
  • Overview

    Updates a single row in the table. Under certain conditions, it may insert or delete a row as well.

    Parameters

    Returns Promise<void>

    A promise which resolves once the operation is completed.

    Example

    await table.insertOne({ key: '123', name: 'Jerry' });
    await table.updateOne({ key: '123' }, { $set: { name: 'Geraldine' } });
    Upserting

    If the row doesn't exist, and you're $set-ing at least one row to a non-null value, an upsert will occur.

    Example

    // No upsert will occur here since only nulls are being set
    // (this is equivalent to `{ $unset: { name: '' } }`)
    await table.updateOne({ key: '123' }, { $set: { name: null } });

    // An upsert will occur here since at least one non-null value is being set
    await table.updateOne({ key: '123' }, { $set: { name: 'Eleanor', age: null } });
    Deleting

    If the row was only upserted in the first place, and now all (non-primary) rows are set to null (or unset), the row will be deleted.

    If the row was inserted on, even if it was upserted first, it will not be deleted.

    Note that $set-ing a row to null is equivalent to $unset-ing it. The following example would be the exact same using $unsets.

    Example

    // Upserts row { key: '123', name: 'Michael', age: 3 } into the table
    await table.updateOne({ key: '123' }, { $set: { name: 'Michael', age: 3 } });

    // Sets row to { key: '123', name: 'Michael', age: null }
    await table.updateOne({ key: '123' }, { $set: { age: null } });

    // Deletes row from the table as all non-primary keys are set to null
    await table.updateOne({ key: '123' }, { $set: { name: null } });
    Filtering

    The filter must contain an exact primary key to update just one row.

    Attempting to pass an empty filter, filtering by only part of the primary key, or filtering by a non-primary key column will result in an error.

    Update operators

    Updates may perform either $set or$unset operations on the row. ($set-ing a row to null is equivalent to $unset-ing it.)

    On returning void

    The updateOne operation, as returned from the Data API, is always { matchedCount: 1, modifiedCount: 1 }, regardless of how many things are actually matched/modified, and if a row is upserted or not.

    In that sense, returning constantly that one type is isomorphic to just returning void, as both realistically contain the same amount of information (i.e. none)