UniverseQuery 3.0.5
See the version list below for details.
dotnet add package UniverseQuery --version 3.0.5
NuGet\Install-Package UniverseQuery -Version 3.0.5
<PackageReference Include="UniverseQuery" Version="3.0.5" />
<PackageVersion Include="UniverseQuery" Version="3.0.5" />
<PackageReference Include="UniverseQuery" />
paket add UniverseQuery --version 3.0.5
#r "nuget: UniverseQuery, 3.0.5"
#:package UniverseQuery@3.0.5
#addin nuget:?package=UniverseQuery&version=3.0.5
#tool nuget:?package=UniverseQuery&version=3.0.5
Universe
A simpler way of querying a CosmosDb Namespace
Installation
dotnet add package Universe
How-to:
- Your models / cosmos entities should inherit from the base class
public class MyCosmosEntity : CosmicEntity
{
[PartitionKey]
public string FirstName { get; set; }
public string LastName { get; set; }
}
This will allow you to use the PartitionKey
attribute to specify the partition key for your Cosmos DB documents. You can also use multiple partition keys by specifying the order in the attribute, e.g., [PartitionKey(1)]
, [PartitionKey(2)]
, etc.
- Create a repository like so:
public class MyRepository : Galaxy<MyModel>
{
public MyRepository(CosmosClient client, string database, string container, IReadOnlyList<string> partitionKey) : base(client, database, container, partitionKey)
{
}
}
// If you want to see debug information such as the full Query text executed, use the format below:
public class MyRepository : Galaxy<MyModel>
{
public MyRepository(CosmosClient client, string database, string container, IReadOnlyList<string> partitionKey) : base(client, database, container, partitionKey, true)
{
}
}
- In your Startup.cs / Main method / Program.cs, configure the CosmosClient like so:
_ = services.AddScoped(_ => new CosmosClient(
System.Environment.GetEnvironmentVariable("CosmosDbUri"),
System.Environment.GetEnvironmentVariable("CosmosDbPrimaryKey"),
clientOptions: new CosmosClientOptions()
{
Serializer = new UniverseSerializer(), // This is from Universe.Builder.Options
AllowBulkExecution = true // This will tell the underlying code to allow async bulk operations
}
));
Below are the default options for the UniverseSerializer
:
new JsonSerializerOptions()
{
PropertyNamingPolicy = null, // To leave the property names as they are in the model
PropertyNameCaseInsensitive = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
IgnoreReadOnlyFields = true,
IgnoreReadOnlyProperties = true
}
- In your Startup.cs / Main method / Program.cs, configure your CosmosDb repository like so:
_ = services.AddScoped<IGalaxy<MyModel>, MyRepository>(service => new MyRepository(
client: service.GetRequiredService<CosmosClient>(),
database: "database-name",
container: "container-name",
partitionKey: typeof(MyModel).BuildPartitionKey()
));
- Inject your
IGalaxy<MyModel>
dependency into your classes and enjoy a simpler way to query CosmosDb
Understanding the Gravity Object
The Gravity
object is returned by all operations and contains valuable information:
(Gravity gravity, MyModel model) = await galaxy.Get("document-id", "partition-key-value");
// Request Units consumed by the operation
double requestUnits = gravity.RU;
// Continuation token for pagination (only populated in Paged queries)
string continuationToken = gravity.ContinuationToken;
// Query information (only available when debug mode is enabled)
if (gravity.Query.HasValue)
{
string queryText = gravity.Query.Value.Text;
IEnumerable<(string, object)> parameters = gravity.Query.Value.Parameters;
Console.WriteLine($"Query: {queryText}");
foreach ((string name, object value) in parameters)
{
Console.WriteLine($"Parameter: {name} = {value}");
}
}
Examples
This section provides examples of how to use the Galaxy
repository for basic and advanced operations with Cosmos DB.
Here.
Basic Operations
Simple Query Operations
// Get a single document by id and partition key
(Gravity gravity, MyModel model) = await galaxy.Get("document-id", "partition-key-value");
// Basic query with a single filter condition
(Gravity gravity, MyModel model) = await galaxy.Get(
clusters: new List<Cluster>()
{
new Cluster(Catalysts: new List<Catalyst>
{
new Catalyst(nameof(MyModel.PropertyName), "value")
})
}
);
// Get a single document by id and multiple partition keys
(Gravity gravity, MyModel model) = await galaxy.Get("document-id", "partition-key-value1", "partition-key-value2");
Creating Documents
// Create a single document
MyModel model = new MyModel
{
PropertyName = "value",
// Set other properties
};
(Gravity gravity, string id) = await galaxy.Create(model);
// Bulk create multiple documents
List<MyModel> models = new List<MyModel>
{
new MyModel { /* properties */ },
new MyModel { /* properties */ }
};
Gravity gravity = await galaxy.Create(models);
Updating Documents
// Update a single document
model.PropertyName = "new value";
(Gravity gravity, MyModel updatedModel) = await galaxy.Modify(model);
// Bulk update multiple documents
foreach (MyModel item in models)
{
item.PropertyName = "new value";
}
Gravity gravity = await galaxy.Modify(models);
Deleting Documents
// Delete a document
Gravity gravity = await galaxy.Remove("document-id", "partition-key-value");
// Delete a document by id and multiple partition keys
Gravity gravity = await galaxy.Remove("document-id", "partition-key-value1", "partition-key-value2");
Advanced Query Examples
Complex Queries with Multiple Conditions
// Query with multiple conditions in a single cluster
(Gravity gravity, IList<MyModel> results) = await galaxy.List(
clusters: new List<Cluster>()
{
new Cluster(Catalysts: new List<Catalyst>
{
new Catalyst(nameof(MyModel.PropertyName), "value"),
new Catalyst(nameof(MyModel.NumberProperty), 123, Where: Q.Where.And)
})
}
);
// Query with multiple clusters (combining conditions with AND/OR)
(Gravity gravity, IList<MyModel> results) = await galaxy.List(
clusters: new List<Cluster>()
{
new Cluster(Catalysts: new List<Catalyst>
{
new Catalyst(nameof(MyModel.PropertyName), "value"),
new Catalyst(nameof(MyModel.AnotherProperty), 123, Where: Q.Where.Or)
}, Where: Q.Where.And),
new Cluster(Catalysts: new List<Catalyst>
{
new Catalyst(nameof(MyModel.Status), "Active")
})
}
);
Special Operators
// Using In operator for array properties
(Gravity gravity, IList<MyModel> results) = await galaxy.List(
clusters: new List<Cluster>()
{
new Cluster(Catalysts: new List<Catalyst>
{
new Catalyst(nameof(MyModel.Tags), "tag1", Operator: Q.Operator.In)
})
}
);
// Check if a property is defined
(Gravity gravity, IList<MyModel> results) = await galaxy.List(
clusters: new List<Cluster>()
{
new Cluster(Catalysts: new List<Catalyst>
{
new Catalyst(nameof(MyModel.OptionalProperty), Operator: Q.Operator.Defined)
})
}
);
// Comparison operators
(Gravity gravity, IList<MyModel> results) = await galaxy.List(
clusters: new List<Cluster>()
{
new Cluster(Catalysts: new List<Catalyst>
{
new Catalyst(nameof(MyModel.NumberProperty), 100, Operator: Q.Operator.Gt)
})
}
);
Sorting and Column Selection
// Query with sorting
(Gravity gravity, IList<MyModel> results) = await galaxy.List(
clusters: new List<Cluster>() { /* query conditions */ },
sorting: new List<Sorting.Option>
{
new Sorting.Option(nameof(MyModel.PropertyName), Sorting.Direction.DESC)
}
);
// Query with column selection
(Gravity gravity, IList<MyModel> results) = await galaxy.List(
clusters: new List<Cluster>() { /* query conditions */ },
columnOptions: new ColumnOptions(
Names: new List<string>
{
nameof(MyModel.id),
nameof(MyModel.PropertyName),
nameof(MyModel.AnotherProperty)
}
)
);
// Using TOP to limit results
(Gravity gravity, IList<MyModel> results) = await galaxy.List(
clusters: new List<Cluster>() { /* query conditions */ },
columnOptions: new ColumnOptions(
Names: new List<string>
{
nameof(MyModel.id),
nameof(MyModel.PropertyName)
},
Top: 10
)
);
// Using DISTINCT
(Gravity gravity, IList<MyModel> results) = await galaxy.List(
clusters: new List<Cluster>() { /* query conditions */ },
columnOptions: new ColumnOptions(
Names: new List<string>
{
nameof(MyModel.PropertyName)
},
IsDistinct: true
)
);
Pagination
// First page
(Gravity gravity, IList<MyModel> items) = await galaxy.Paged(
page: new Q.Page(25), // 25 items per page
clusters: new List<Cluster>() { /* query conditions */ }
);
// Access continuation token from the gravity object
string continuationToken = gravity.ContinuationToken;
// Next page using continuation token
(Gravity nextGravity, IList<MyModel> nextItems) = await galaxy.Paged(
page: new Q.Page(25, continuationToken),
clusters: new List<Cluster>() { /* same query conditions */ }
);
See example 1.
Aggregation and Group By Queries
// Group by a property
(Gravity gravity, IList<MyModel> results) = await galaxy.List(
clusters: new List<Cluster>() { /* query conditions */ },
group: new List<string> { nameof(MyModel.Category) }
);
// Using aggregation functions with ColumnOptions.Aggregates
(Gravity gravity, IList<MyModel> results) = await galaxy.List(
clusters: new List<Cluster>() { /* query conditions */ },
columnOptions: new ColumnOptions(
Names: new List<string> { nameof(MyModel.Category) },
Aggregates: [
new AggregationOption(nameof(MyModel.Price), Q.Aggregate.Sum),
new AggregationOption(nameof(MyModel.Quantity), Q.Aggregate.Count)
]
)
);
// Multiple aggregation functions in one query
(Gravity gravity, IList<MyModel> results) = await galaxy.List(
clusters: new List<Cluster>() { /* query conditions */ },
columnOptions: new ColumnOptions(
Names: new List<string> { nameof(MyModel.Category) },
Aggregates: [
new AggregationOption(nameof(MyModel.Price), Q.Aggregate.Sum),
new AggregationOption(nameof(MyModel.Price), Q.Aggregate.Avg),
new AggregationOption(nameof(MyModel.Quantity), Q.Aggregate.Max)
]
)
);
The Aggregates
parameter in ColumnOptions
takes an array of AggregationOption
structs, each specifying a column name and an aggregate function to apply. It supports the following aggregate functions:
Q.Aggregate.Count
: Counts the number of itemsQ.Aggregate.Sum
: Calculates the sum of the specified columnQ.Aggregate.Min
: Finds the minimum value of the specified columnQ.Aggregate.Max
: Finds the maximum value of the specified columnQ.Aggregate.Avg
: Calculates the average of the specified column
When using aggregates, the query will automatically be grouped by the columns specified in the Names
parameter. The output column names will be suffixed with the aggregate function name (e.g., Price_Sum
, Price_Avg
, Quantity_Max
).
See example 2, example 7, example 8.
Vector Distance Search
The Universe library supports vector similarity search through the Q.Operator.VectorDistance
operator, which leverages Azure Cosmos DB's built-in vector search capabilities.
See the VECTORDISTANCE_USAGE.md
Full-Text Search
The Universe library provides a simple way to perform full-text search queries using the Q.Operator.FT*
operators. This allows you to search for documents containing specific text in designated fields.
See the FULLTEXT_USAGE.md
Stored Procedures
You can manage and execute Cosmos DB stored procedures using the IGalaxyProcedure
interface. Inject your repository as IGalaxyProcedure
and use its methods for full stored procedure lifecycle management and execution.
IGalaxyProcedure galaxyProcedure = ...; // Injected or resolved from DI
// Execute a stored procedure and get a result of type T
(Gravity gravity, MyModel result) = await galaxyProcedure.ExecSProc<MyModel>(
procedureName: "myStoredProcedure",
partitionKey: "partition-key-value",
parameters: new object[] { /* procedure parameters */ }
);
// Create a new stored procedure
Gravity createResult = await galaxyProcedure.CreateSProc(
procedureName: "myStoredProcedure",
body: "function (...) { /* JS code */ }"
);
// Read a stored procedure's body
(Gravity readGravity, string body) = await galaxyProcedure.ReadSProc("myStoredProcedure");
// Replace an existing stored procedure
Gravity replaceResult = await galaxyProcedure.ReplaceSProc(
procedureName: "myStoredProcedure",
newBody: "function (...) { /* new JS code */ }"
);
// Delete a stored procedure
Gravity deleteResult = await galaxyProcedure.DeleteSProc("myStoredProcedure");
// List all stored procedure names
(Gravity listGravity, IList<string> names) = await galaxyProcedure.ListSProcs();
ExecSProc<T>
: Executes a stored procedure and returns a tuple ofGravity
and the deserialized result of typeT
.CreateSProc
: Creates a new stored procedure with the given name and body.ReadSProc
: Reads the body of a stored procedure.ReplaceSProc
: Replaces the body of an existing stored procedure.DeleteSProc
: Deletes a stored procedure by name.ListSProcs
: Lists all stored procedure names in the container.
The Gravity
object provides RU and diagnostic information for each operation.
Error Handling
try
{
(Gravity gravity, MyModel model) = await galaxy.Get("non-existent-id", "partition-key");
}
catch (UniverseException ex)
{
// Universe-specific exceptions
Console.WriteLine($"Universe error: {ex.Message}");
}
catch (CosmosException ex)
{
// Cosmos DB specific exceptions
Console.WriteLine($"Cosmos error: {ex.Message}, Status: {ex.StatusCode}");
}
catch (Exception ex)
{
// Other errors
Console.WriteLine($"Error: {ex.Message}");
}
Performance Considerations
- Bulk Operations: Enable
AllowBulkExecution
in the CosmosClientOptions for efficient batch processing. - RU Tracking: The
Gravity
object provides RU consumption information for cost optimization. - Column Selection: Select only the columns you need to reduce data transfer.
- Debug Mode: The debug mode (enabled by passing
true
to the Galaxy constructor) provides query details but adds overhead. - Partition Key: Always consider your partition strategy for best performance.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- Microsoft.Azure.Cosmos (>= 3.53.0-preview.0)
- Newtonsoft.Json (>= 13.0.3)
- System.Text.Json (>= 9.0.7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
3.1.0-preview.4 | 34 | 8/28/2025 |
3.1.0-preview.3 | 31 | 8/28/2025 |
3.1.0-preview.2 | 35 | 8/28/2025 |
3.1.0-preview.1 | 71 | 8/25/2025 |
3.0.6-preview.2 | 498 | 8/18/2025 |
3.0.5 | 460 | 8/5/2025 |
3.0.4 | 136 | 7/15/2025 |
3.0.3 | 102 | 6/27/2025 |
3.0.2 | 78 | 5/31/2025 |
2.1.0 | 491 | 3/25/2025 |
2.0.1 | 223 | 9/24/2023 |
2.0.0 | 326 | 3/31/2023 |
1.4.1 | 656 | 1/20/2023 |
1.4.0 | 936 | 10/20/2022 |
1.3.2 | 666 | 10/11/2022 |
1.2.1 | 882 | 8/22/2022 |
1.2.0 | 511 | 8/12/2022 |
1.1.4 | 556 | 8/5/2022 |