Find a row (C#)

Finds a single row in a table using filter and sort clauses, including vector search.

For general information about working with tables and rows, see About tables with the Data API (C#).

Ready to write code? See the examples for this method to get started. If you are new to the Data API, check out the quickstart.

Result

Returns a row that matches the specified filter and sort clauses, or returns null if no row was found.

The columns included in the returned row depend on the subset of columns that were requested in the projection. If requested and applicable, the row will also include a $similarity key with a numeric similarity score that represents the closeness of the sort vector and the row’s vector.

Parameters

Use the FindOneAsync method, which belongs to the Table class. You can also use FindOne, which is the synchronous version of the method.

Method signature
public Task<T> FindOneAsync(TableFindOneOptions<T> findOptions = null);
public Task<T> FindOneAsync(
  TableFilter<T> filter,
  TableFindOneOptions<T> options = null
);
public Task<TResult> FindOneAsync<TResult>(
  TableFindOneOptions<T> findOptions = null
) where TResult : class;
public Task<TResult> FindOneAsync<TResult>(
  TableFilter<T> filter, TableFindOneOptions<T> options = null
) where TResult : class;

For best performance, filter and sort on indexed columns, partition keys, and clustering keys.

Filtering on non-indexed columns is inefficient and resource-intensive, especially for large datasets. With the Data API clients, such operations can hit the client timeout limit before the underlying HTTP operation is complete. If you filter on non-indexed columns, the Data API will give a warning.

An empty filter or omitted filter may also result in an inefficient and long-running operation.

Additionally, the Data API can perform in-memory sorting, depending on the columns you sort on, the table’s partitioning structure, and whether the sorted columns are indexed. In-memory sorts can have performance implications.

Name Type Summary

filter

TableFilter

Optional. An object that defines filter criteria using the Data API filter syntax. The method only finds rows that match the filter criteria. Filters can improve performance by reducing the number of rows that the Data API processes.

For a list of available filter operators and more examples, see Filter operators for tables (C#).

To perform a vector search, use sort instead of filter.

To avoid fetching unnecessary rows, which can contain tombstones, DataStax recommends that you use a filter that limits the number of rows scanned. For example, filter on partition key columns or indexed columns.

Default: No filter

For an example, see Use filters to find a row.

options

TableFindOneOptions

Optional. Options for this operation. For more information and examples for general options such as timeout, see Customize API interaction. For options specific to this method, see Method-specific properties of the TableFindOneOptions class.

Method-specific properties of the TableFindOneOptions class
Name Type Summary

Projection

IProjectionBuilder

Optional. Controls which columns are included or excluded in the returned rows.

For more information, see Projections for tables (C#).

DataStax recommends a projection to avoid unnecessarily returning large columns, such as vector columns with highly dimensional embeddings.

Default: All columns

Sort

SortBuilder<T>

Optional. Sorts rows by one or more columns, or performs a vector search.

For more information, see Sort clauses for tables (C#).

Examples

The following examples demonstrate how to find a row in a table.

Use filters to find a row

You can use a filter to find a row that matches specific criteria. For example, you can find a row with an is_checked_out value of false and a number_of_pages value less than 300.

For optimal performance, only filter on indexed columns. The Data API returns a warning if you filter on a non-indexed column.

For a list of available filter operators, see Filter operators for tables (C#).

  • Typed

  • Untyped

You can manually define a client-side type for your table to help statically catch errors. For more information and examples, see Custom typing for tables.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Book
{
  [ColumnPrimaryKey(1)]
  [ColumnName("title")]
  public string Title { get; set; } = null!;

  [ColumnPrimaryKey(2)]
  [ColumnName("author")]
  public string Author { get; set; } = null!;

  [ColumnName("number_of_pages")]
  public int? NumberOfPages { get; set; }

  [ColumnName("genres")]
  public HashSet<string>? Genres { get; set; }

  [ColumnName("is_checked_out")]
  public bool? IsCheckedOut { get; set; }
}

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable<Book>("TABLE_NAME");

    // Find a row
    var filterBuilder = Builders<Book>.TableFilter;
    var filter = filterBuilder.And(
      filterBuilder.Eq(b => b.IsCheckedOut, false),
      filterBuilder.Lt(b => b.NumberOfPages, 300)
    );

    var result = await table.FindOneAsync(filter);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

If you don’t pass a type parameter, the collection or table remains untyped. This is a more flexible but less type-safe option.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable("TABLE_NAME");

    // Find a row
    var filterBuilder = Builders<Row>.TableFilter;
    var filter = filterBuilder.And(
      filterBuilder.Eq("is_checked_out", false),
      filterBuilder.Lt("number_of_pages", 300)
    );

    var result = await table.FindOneAsync(filter);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

Use vector search with a search vector to find a row

Perform a vector search by providing a search vector in the sort clause. This returns the row whose vector column value is most similar to the provided search vector.

The vector column must be indexed.

If your table has multiple vector columns, you can only sort on one vector column at a time.

The client automatically binary-encodes your search vector.

  • Typed

  • Untyped

You can manually define a client-side type for your table to help statically catch errors. For more information and examples, see Custom typing for tables.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Book
{
  [ColumnPrimaryKey(1)]
  [ColumnName("title")]
  public string Title { get; set; } = null!;

  [ColumnPrimaryKey(2)]
  [ColumnName("author")]
  public string Author { get; set; } = null!;

  [ColumnVector(5)]
  [ColumnName("summary_genres_vector")]
  public object? SummaryGenresVector { get; set; }
}

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable<Book>("TABLE_NAME");

    // Find a row
    var embeddings = new float[] { 0.08f, -0.62f, 0.39f };
    var findOptions = new TableFindOneOptions<Book>()
    {
      Sort = Builders<Book>.TableSort.Vector(
        b => b.SummaryGenresVector,
        embeddings
      ),
    };
    var result = await table.FindOneAsync(findOptions);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

If you don’t pass a type parameter, the collection or table remains untyped. This is a more flexible but less type-safe option.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable("TABLE_NAME");

    // Find a row
    var embeddings = new float[] { 0.08f, -0.62f, 0.39f };
    var findOptions = new TableFindOneOptions<Row>()
    {
      Sort = Builders<Row>.TableSort.Vector(
        "summary_genres_vector",
        embeddings
      ),
    };
    var result = await table.FindOneAsync(findOptions);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

Use lexicographical matching to find a row

Lexicographical matching is currently in public preview. Development is ongoing, and the features and functionality are subject to change. Hyper-Converged Database (HCD), and the use of such, is subject to the DataStax Preview Terms.

There are two ways to use lexicographical matching to find rows with the Data API:

  • Sort to find rows with a text or ascii column value that is most relevant to a given string of space-separated keywords or terms.

  • Filter with the $match operator to find rows with a text or ascii column value that is a lexicographical match to the specified string of space-separated keywords or terms

You can use these strategies together or separately.

Lexicographical matching is only available for text or ascii columns that have a text index, not a regular index. For more information, see Create a text index (C#) and Indexes in tables (C#).

  • Typed

  • Untyped

You can manually define a client-side type for your table to help statically catch errors. For more information and examples, see Custom typing for tables.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Book
{
  [ColumnPrimaryKey(1)]
  [ColumnName("title")]
  public string Title { get; set; } = null!;

  [ColumnPrimaryKey(2)]
  [ColumnName("author")]
  public string Author { get; set; } = null!;

  [ColumnName("summary")]
  public string Summary { get; set; } = null!;
}

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable<Book>("TABLE_NAME");

    // Find a row
    var filterBuilder = Builders<Book>.TableFilter;
    var filter = filterBuilder.LexicalMatch(
      b => b.Summary,
      "futuristic laboratory discovery"
    );
    var findOptions = new TableFindOneOptions<Book>()
    {
      Sort = Builders<Book>.TableSort.Lexical(
        b => b.Summary,
        "futuristic laboratory"
      ),
    };
    var result = await table.FindOneAsync(filter, findOptions);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

If you don’t pass a type parameter, the collection or table remains untyped. This is a more flexible but less type-safe option.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable("TABLE_NAME");

    // Find a row
    var filterBuilder = Builders<Row>.TableFilter;
    var filter = filterBuilder.LexicalMatch(
      "summary",
      "futuristic laboratory discovery"
    );
    var findOptions = new TableFindOneOptions<Row>()
    {
      Sort = Builders<Row>.TableSort.Lexical(
        "summary",
        "futuristic laboratory"
      ),
    };
    var result = await table.FindOneAsync(filter, findOptions);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

Use sorting to find a row

You can use a sort clause to sort rows by one or more columns.

For best performance, only sort on columns that are indexed or that are part of the primary key.

For more information, see Sort clauses for tables (C#).

  • Typed

  • Untyped

You can manually define a client-side type for your table to help statically catch errors. For more information and examples, see Custom typing for tables.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Book
{
  [ColumnPrimaryKey(1)]
  [ColumnName("title")]
  public string Title { get; set; } = null!;

  [ColumnPrimaryKey(2)]
  [ColumnName("author")]
  public string Author { get; set; } = null!;

  [ColumnName("rating")]
  public float? Rating { get; set; }
}

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable<Book>("TABLE_NAME");

    // Find a row
    var findOptions = new TableFindOneOptions<Book>()
    {
      Sort = Builders<Book>
        .TableSort.Ascending(b => b.Rating)
        .Descending(b => b.Title),
    };
    var result = await table.FindOneAsync(findOptions);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

If you don’t pass a type parameter, the collection or table remains untyped. This is a more flexible but less type-safe option.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable("TABLE_NAME");

    // Find a row
    var findOptions = new TableFindOneOptions<Row>()
    {
      Sort = Builders<Row>
        .TableSort.Ascending("rating")
        .Descending("title"),
    };
    var result = await table.FindOneAsync(findOptions);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

Include the similarity score with the result

If you use a vector search to find a row, you can also include a $similarity property in the result. The $similarity value represents the closeness of the sort vector and the value of the row’s vector column.

This parameter doesn’t work with vectorize; it only works if you provide the search vector for vector search directly.

  • Typed

  • Untyped

You can manually define a client-side type for your table to help statically catch errors. For more information and examples, see Custom typing for tables.

If you use a strongly typed object for your row, you must add a property with the [DocumentMapping(DocumentMappingField.Similarity)] attribute to that object to handle receiving the similarity score.

using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.SerDes;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Book
{
  [ColumnPrimaryKey(1)]
  [ColumnName("title")]
  public string Title { get; set; } = null!;

  [ColumnPrimaryKey(2)]
  [ColumnName("author")]
  public string Author { get; set; } = null!;

  [ColumnVector(dimension: 3)]
  [ColumnName("summary_genres_vector")]
  public float[]? SummaryGenresVector { get; set; }

  [ColumnIgnore]
  [ColumnMapping(ColumnMappingField.Similarity)]
  public double? Similarity { get; set; }
}

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable<Book>("TABLE_NAME");

    // Find a row
    var findOptions = new TableFindOneOptions<Book>()
    {
      Sort = Builders<Book>.TableSort.Vector(
        b => b.SummaryGenresVector,
        new float[] { 0.08f, -0.62f, 0.39f }
      ),
      IncludeSimilarity = true,
    };
    var result = await table.FindOneAsync(findOptions);

    if (result != null)
    {
      Console.WriteLine(result.Similarity);
    }
  }
}

If you don’t pass a type parameter, the collection or table remains untyped. This is a more flexible but less type-safe option.

using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable("TABLE_NAME");

    // Find a row
    var findOptions = new TableFindOneOptions<Row>()
    {
      Sort = Builders<Row>.TableSort.Vector(
        "summary_genres_vector",
        new float[] { 0.08f, -0.62f, 0.39f }
      ),
      IncludeSimilarity = true,
    };
    var result = await table.FindOneAsync(findOptions);

    if (result != null)
    {
      Console.WriteLine(result["$similarity"]);
    }
  }
}

Include only specific columns in the response

To specify which columns to include or exclude in the returned row, use a projection.

The following example demonstrates an inclusive projection.

  • Typed

  • Untyped

You can manually define a client-side type for your table to help statically catch errors. For more information and examples, see Custom typing for tables.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Book
{
  [ColumnPrimaryKey(1)]
  [ColumnName("title")]
  public string Title { get; set; } = null!;

  [ColumnPrimaryKey(2)]
  [ColumnName("author")]
  public string Author { get; set; } = null!;

  [ColumnName("number_of_pages")]
  public int? NumberOfPages { get; set; }

  [ColumnName("is_checked_out")]
  public bool? IsCheckedOut { get; set; }
}

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable<Book>("TABLE_NAME");

    // Find a row
    var filterBuilder = Builders<Book>.TableFilter;
    var filter = filterBuilder.And(
      filterBuilder.Eq(b => b.IsCheckedOut, false),
      filterBuilder.Lt(b => b.NumberOfPages, 300)
    );

    var findOptions = new TableFindOneOptions<Book>()
    {
      Projection = Builders<Book>
        .Projection.Include(b => b.IsCheckedOut)
        .Include(b => b.Title),
    };

    var result = await table.FindOneAsync(filter, findOptions);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

If you don’t pass a type parameter, the collection or table remains untyped. This is a more flexible but less type-safe option.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable("TABLE_NAME");

    // Find a row
    var filterBuilder = Builders<Row>.TableFilter;
    var filter = filterBuilder.And(
      filterBuilder.Eq("is_checked_out", false),
      filterBuilder.Lt("number_of_pages", 300)
    );

    var findOptions = new TableFindOneOptions<Row>()
    {
      Projection = Builders<Row>
        .Projection.Include("is_checked_out")
        .Include("title"),
    };

    var result = await table.FindOneAsync(filter, findOptions);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

Exclude specific columns from the response

To specify which columns to include or exclude in the returned row, use a projection.

The following example demonstrates an exclusive projection.

  • Typed

  • Untyped

You can manually define a client-side type for your table to help statically catch errors. For more information and examples, see Custom typing for tables.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Book
{
  [ColumnPrimaryKey(1)]
  [ColumnName("title")]
  public string Title { get; set; } = null!;

  [ColumnPrimaryKey(2)]
  [ColumnName("author")]
  public string Author { get; set; } = null!;

  [ColumnName("number_of_pages")]
  public int? NumberOfPages { get; set; }

  [ColumnName("is_checked_out")]
  public bool? IsCheckedOut { get; set; }
}

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable<Book>("TABLE_NAME");

    // Find a row
    var filterBuilder = Builders<Book>.TableFilter;
    var filter = filterBuilder.And(
      filterBuilder.Eq(b => b.IsCheckedOut, false),
      filterBuilder.Lt(b => b.NumberOfPages, 300)
    );

    var findOptions = new TableFindOneOptions<Book>()
    {
      Projection = Builders<Book>
        .Projection.Exclude(b => b.IsCheckedOut)
        .Exclude(b => b.Title),
    };

    var result = await table.FindOneAsync(filter, findOptions);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

If you don’t pass a type parameter, the collection or table remains untyped. This is a more flexible but less type-safe option.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable("TABLE_NAME");

    // Find a row
    var filterBuilder = Builders<Row>.TableFilter;
    var filter = filterBuilder.And(
      filterBuilder.Eq("is_checked_out", false),
      filterBuilder.Lt("number_of_pages", 300)
    );

    var findOptions = new TableFindOneOptions<Row>()
    {
      Projection = Builders<Row>
        .Projection.Exclude("is_checked_out")
        .Exclude("title"),
    };

    var result = await table.FindOneAsync(filter, findOptions);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

Use filter, sort, and projection together

  • Typed

  • Untyped

You can manually define a client-side type for your table to help statically catch errors. For more information and examples, see Custom typing for tables.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Book
{
  [ColumnPrimaryKey(1)]
  [ColumnName("title")]
  public string Title { get; set; } = null!;

  [ColumnPrimaryKey(2)]
  [ColumnName("author")]
  public string Author { get; set; } = null!;

  [ColumnName("number_of_pages")]
  public int? NumberOfPages { get; set; }

  [ColumnName("rating")]
  public float? Rating { get; set; }

  [ColumnName("is_checked_out")]
  public bool? IsCheckedOut { get; set; }
}

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable<Book>("TABLE_NAME");

    // Find a row
    var filterBuilder = Builders<Book>.TableFilter;
    var filter = filterBuilder.And(
      filterBuilder.Eq(b => b.IsCheckedOut, false),
      filterBuilder.Lt(b => b.NumberOfPages, 300)
    );

    var findOptions = new TableFindOneOptions<Book>()
    {
      Sort = Builders<Book>
        .TableSort.Ascending(b => b.Rating)
        .Descending(b => b.Title),
      Projection = Builders<Book>
        .Projection.Include(b => b.IsCheckedOut)
        .Include(b => b.Title),
    };

    var result = await table.FindOneAsync(filter, findOptions);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

If you don’t pass a type parameter, the collection or table remains untyped. This is a more flexible but less type-safe option.

using System.Text.Json;
using DataStax.AstraDB.DataApi;
using DataStax.AstraDB.DataApi.Core;
using DataStax.AstraDB.DataApi.Core.Query;
using DataStax.AstraDB.DataApi.Tables;

namespace Examples;

public class Program
{
  static async Task Main()
  {
    // Get an existing table
    var client = new DataAPIClient(
      new CommandOptions() { Destination = DataAPIDestination.HCD }
    );

    var database = client.GetDatabase(
      "API_ENDPOINT",
      DataAPIClient.UsernamePasswordTokenProvider(
        "USERNAME",
        "PASSWORD"
      ),
      "KEYSPACE_NAME"
    );

    var table = database.GetTable("TABLE_NAME");

    // Find a row
    var filterBuilder = Builders<Row>.TableFilter;
    var filter = filterBuilder.And(
      filterBuilder.Eq("is_checked_out", false),
      filterBuilder.Lt("number_of_pages", 300)
    );

    var findOptions = new TableFindOneOptions<Row>()
    {
      Sort = Builders<Row>
        .TableSort.Ascending("rating")
        .Descending("title"),
      Projection = Builders<Row>
        .Projection.Include("is_checked_out")
        .Include("title"),
    };

    var result = await table.FindOneAsync(filter, findOptions);

    Console.WriteLine(JsonSerializer.Serialize(result));
  }
}

Client reference

For more information, see the client reference.

Was this helpful?

Give Feedback

How can we improve the documentation?

© Copyright IBM Corporation 2026 | Privacy policy | Terms of use Manage Privacy Choices

Apache, Apache Cassandra, Cassandra, Apache Tomcat, Tomcat, Apache Lucene, Apache Solr, Apache Hadoop, Hadoop, Apache Pulsar, Pulsar, Apache Spark, Spark, Apache TinkerPop, TinkerPop, Apache Kafka and Kafka are either registered trademarks or trademarks of the Apache Software Foundation or its subsidiaries in Canada, the United States and/or other countries. Kubernetes is the registered trademark of the Linux Foundation.

General Inquiries: Contact IBM