|
| 1 | += C# client usage |
| 2 | +:description: Guidance for using the {data-api} C# client. |
| 3 | + |
| 4 | +This page provides language-specific guidance for using the data-api C# client. |
| 5 | + |
| 6 | +For information about installing and getting started with the C# client, see ???. |
| 7 | + |
| 8 | +== Terminology |
| 9 | + |
| 10 | +The Data API stores structured data as `Documents` which are essentially key-value pairs. In the C# client these documents will be represented by C# classes (POCOs) or, at the lowest level, by dictionaries. When we refer to "fields" or "properties" we are referring to these key-value pairs and/or their representative members in the C# classes, not specifying the C# implementation. |
| 11 | + |
| 12 | +== Client hierarchy |
| 13 | + |
| 14 | +All interactions with the data begin with a DataApiClient object. |
| 15 | + |
| 16 | +Once you have an instance of a `DataAPIClient`, you can use it to get an instance of a `Database` object, which can be used to manage and access `Collection` objects which are themselves used to interact with the actual documents. |
| 17 | + |
| 18 | +[source,c#] |
| 19 | +---- |
| 20 | +//instantiate a client |
| 21 | +var client = new DataApiClient("YourTokenHere"); |
| 22 | +
|
| 23 | +//connect to a database |
| 24 | +var database = client.GetDatabase("YourDatabaseUrlHere"); |
| 25 | +
|
| 26 | +//create a new collection |
| 27 | +var collection = await database.CreateCollectionAsync<SimpleObject>("YourCollectionNameHere"); |
| 28 | +
|
| 29 | +//insert a document into the collection |
| 30 | +var newObject = new SimpleObject() |
| 31 | +{ |
| 32 | + Name = "Test Object 1", |
| 33 | +}; |
| 34 | +var insertResult = await collection.InsertOneAsync(newObject); |
| 35 | +var insertedId = insertResult.InsertedId; |
| 36 | +---- |
| 37 | + |
| 38 | +=== Command Options |
| 39 | + |
| 40 | +The `CommandOptions` class provides a set of low-level options to control the interactions with the underlying data store. |
| 41 | + |
| 42 | +These options can be provided at any level of the SDK hierarchy: |
| 43 | + |
| 44 | +* `DataApiClient` |
| 45 | +** `Database` |
| 46 | +*** `Collection` |
| 47 | + |
| 48 | +as well as directly to each of the methods. You can provide different options objects at each level. The options specified at the most granular level will take precedence. |
| 49 | + |
| 50 | +== Serialization and Deserialization |
| 51 | + |
| 52 | +=== Default Behavior |
| 53 | + |
| 54 | +The C# client uses System.Text.Json to handle serializing the documents to JSON to send to the underlying datastore and to deserialize resultant documents back into C# objects. As such, you can use standard System.Text.Json attributes to affect the serialization and deserialization behavior. For example, you can use the `JsonIgnore` attribute to exclude a property from serialization and deserialization. |
| 55 | + |
| 56 | +[source,c#] |
| 57 | +---- |
| 58 | +public class MyDocument |
| 59 | +{ |
| 60 | + public int? _id { get; set; } |
| 61 | + public string Name { get; set; } |
| 62 | + //This property will not be serialized or deserialized |
| 63 | + [JsonIgnore] |
| 64 | + public InternalProperty { get; set; } |
| 65 | +} |
| 66 | +---- |
| 67 | + |
| 68 | +=== Special Fields |
| 69 | + |
| 70 | +While most of the properties passed to the data store are simply serialized to JSON and stored, there are several reserved fields that have special handling. These special fields are identified on your documents by using the `DocumentMappingAttribute`. |
| 71 | + |
| 72 | +The most commonly used special field is `_id`, which is the primary key for the document and is required -- if not provided it will be added by the Data API when storing the document. The Data API can handle multiple types for the `_id` field ([Include link here to documentation on the supported types]). The C# class defining your document can either specifically name a property `_id` or use `DocumentMappingAttribute(DocumentMappingField.Id)` to specify which property should be used as the id. |
| 73 | + |
| 74 | +[source,c#] |
| 75 | +---- |
| 76 | +//This document will use the default id property name |
| 77 | +public class DocumentWithDefaultId |
| 78 | +{ |
| 79 | + public int _id { get; set; } |
| 80 | +} |
| 81 | +
|
| 82 | +//This document will use a custom id property name |
| 83 | +public class CustomIdProperty |
| 84 | +{ |
| 85 | + [DocumentMapping(DocumentMappingField.Id)] |
| 86 | + public Guid ThisIsTheId { get; set; } |
| 87 | +} |
| 88 | +---- |
| 89 | + |
| 90 | +The other field mappings are: |
| 91 | + |
| 92 | +* `DocumentMappingField.Vectorize` - When you want a document to have embeddings automatically generated (based on the vectorize settings for the collection), use this field mapping to specify the text to be vectorized for this document. |
| 93 | + |
| 94 | +* `DocumentMappingField.Vector` - When you generate your own embeddings for a document, these are passed to the Data API through a float array annotated with this field mapping. |
| 95 | + |
| 96 | +* `DocumentMappingField.Similarity` - When performing a vector search on the data, you can specify to include a similarity score for the results. Include this field mapping on a property of the class receiving the results to store the similarity score. |
| 97 | + |
| 98 | +== Handling List Results |
| 99 | + |
| 100 | +For the operations that return a list of documents (i.e. the Find variants), the underlying data is returned in batches by the Data API. The most straightforward way to interact with the data is to simply iterate over the results as an `IAsyncEnumerable<T>` or `IEnumerable<T>`. The enumerable implementations will handle the batch iteration internally. |
| 101 | + |
| 102 | +You can also at this point use all of the standard IEnumerable extensions (e.g. `Skip`, `Take`, `Where`, etc.) to further filter and process the results. |
| 103 | + |
| 104 | +[source,c#] |
| 105 | +---- |
| 106 | +// find all documents |
| 107 | +var results = collection.Find(); |
| 108 | +
|
| 109 | +// synchronous example |
| 110 | +foreach (var doc in results) { |
| 111 | + // do something |
| 112 | +} |
| 113 | +
|
| 114 | +// asynchronous example |
| 115 | +await foreach (var doc in results) |
| 116 | +{ |
| 117 | + // do something |
| 118 | +} |
| 119 | +---- |
| 120 | + |
| 121 | +If you need to manually control the batch iteration, you can use the `Cursor` class by calling ToCursor() on the results. |
| 122 | + |
| 123 | +[source,c#] |
| 124 | +---- |
| 125 | +// find all documents |
| 126 | +var cursor = collection.Find().ToCursor(); |
| 127 | +
|
| 128 | +// synchronous example |
| 129 | +while (cursor.MoveNext()) |
| 130 | +{ |
| 131 | + var batch = cursor.Current; |
| 132 | + foreach (var doc in batch) { |
| 133 | + // do something |
| 134 | + } |
| 135 | +} |
| 136 | +
|
| 137 | +// asynchronous example |
| 138 | +while (await cursor.MoveNextAsync()) |
| 139 | +{ |
| 140 | + var batch = cursor.Current; |
| 141 | + // do something with batch |
| 142 | +} |
| 143 | +---- |
0 commit comments