We have next entity:
public class Product
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;
[BsonExtraElements]
public Dictionary<string, object?> AdditionalData { get; set; } = new();
}
This entity can have many dynamic data that can be stored inside AdditionalData
property. Using attribute BsonExtraElements
we can save these data to MongoDb
perfectly. Our data will be stored as separated properties. It is exactly what we want to save on Storage Level.
After it we implemented all steps hat described in instruction.
So we designed next ObjectType
:
public class ProductType : ObjectType<Product>
{
private readonly List<EntityFieldDescriptor> _fields;
public ProductType(ICollection<EntityFieldDescriptor> fields)
{
// There provided or "dynamic" properties for specific entity
_fields = fields;
}
protected override void Configure(IObjectTypeDescriptor<Product> descriptor)
{
descriptor.Field(f => f.Id).ID().Name("id");
descriptor.Field(f => f.Name).Name("name");
descriptor.Ignore(entity => entity.AdditionalData);
foreach (var field in _fields)
{
descriptor
.Field(field.Name)
.Type(Type.GetType(field.ValueType)!)
.Resolve(resolver => resolver.Parent<Product>().AdditionalData.GetValueOrDefault(field.Name));
}
descriptor.BindFieldsImplicitly();
}
}
And query:
public partial class Query
{
[UseProjection]
[UseSorting]
[UseFiltering]
public IExecutable<Product> GetProducts(
[Service] IMongoCollection<Product> collection)
{
return collection.AsExecutable();
}
[UseFirstOrDefault]
public IExecutable<Product> GetProductById(
[Service] IMongoCollection<Product> collection,
[ID(nameof(Product))] Guid id)
{
return collection.Find(x => x.Id == id).AsExecutable();
}
}
And service registration:
services.AddGraphQLServer()
.AddType<ProductType>()
.AddQueryType<Query>()
.AddMongoDbFiltering()
.AddMongoDbSorting()
.AddMongoDbProjections()
.AddMongoDbPagingProviders();
Using this configuration we can work with predefined properties very well.
We can run next query perfectly:
query {
products(where: { name: { eq: "test" }}) {
id,
material # It is our "dynamic" field
}
}
Our goal to use "dynamic" field inside where
clause. Example: where: {material: { eq: "cuprum" }}
Of course our filter schema do not know nothing about "dynamic" fields. So we defined next FilterInputType
very similar to ObjectType
:
public class ProductFilterType : FilterInputType<Product>
{
private readonly List<EntityFieldDescriptor> _fields;
public ProductFilterType(ICollection<EntityFieldDescriptor> collection)
{
// There provided or "dynamic" properties for specific entity
_fields = fields;
}
protected override void Configure(IFilterInputTypeDescriptor<Product> descriptor)
{
descriptor.Field(f => f.Code).Name("code");
descriptor.Ignore(entity => entity.AdditionalData);
foreach (var field in _fields)
{
descriptor.Field(field.Name).Type(typeof(StringOperationFilterInputType));
}
descriptor.BindFieldsImplicitly();
}
}
After creation of this FilterInputType
we will be able to run our GraphQL query to server.
But when Hotchocolate
run our query then we have an error:
Is it possible to use filtration/sorting/pagination of BsonExtraElements
using Hotchocolate
library?
Will be gratefull to any help!