0

Let's assume that I have the following documents in mongo:

Product:

  • ...
  • productTemplateId
  • ...

Product Template:

  • id
  • ...

I mapped product to the following schema:

product {
 ...
 productTemplate {
  id,
  ...
 }
 ...
}
  1. I would like to avoid to make additional call when I ask only for product { productTemplate {id}} because this information is in the product entity. Is it possible?
  2. I would like to get from mongo only product with productTemplateId instead of whole document. It is significant because I have about 100 req/s. Is it possible to ask mongo only for expected fields from document?

This is part of my code:

public class ProductType : ObjectType<ProductDocument>
{
    protected override void Configure(IObjectTypeDescriptor<ProductDocument> descriptor)
    {
        descriptor.BindFieldsExplicitly();
        descriptor.Name("Product");            
        descriptor.Field("productTemplate")
            .Type<ProductTemplateType>()
            .ResolveWith<ProductTemplatesResolver>(r => r.GetProductTemplate(default!, default!, default));
    }
}

public class ProductTemplatesResolver
{
    public Task<ProductTemplateDocument> GetProductTemplate([Parent] ProductDocument product,
        ProductTemplatesBatchDataLoader loader,
        CancellationToken cancellationToken)
    {
        return loader.LoadAsync(product.ProductTemplateId, cancellationToken);
    }
}

public class ProductTemplatesBatchDataLoader : BatchDataLoader<int, ProductTemplateDocument>
{
    private readonly ProductsDbContext _dbContext;
    
    public ProductTemplatesBatchDataLoader(IBatchScheduler batchScheduler, ProductsDbContext dbContext, DataLoaderOptions? options = null) : base(batchScheduler, options)
    {
        _dbContext = dbContext;
    }

    protected override async Task<IReadOnlyDictionary<int, ProductTemplateDocument>> LoadBatchAsync(IReadOnlyList<int> keys, CancellationToken cancellationToken)
    {
        var pts = await _dbContext.ProductTemplates
            .AsQueryable()
            .Where(x => keys.Contains(x.Id))
            .ToListAsync(cancellationToken);

        return pts.ToDictionary(x => x.Id, x => x);
    }
}

Thanks

Radek
  • 37
  • 5

1 Answers1

1

You can get the selected field over IResolverContext GetSelections

public class ProductTemplatesResolver
{
    public Task<ProductTemplateDocument> GetProductTemplate(
        [Parent] ProductDocument product,
        IResolverContext context,
        ProductTemplatesBatchDataLoader loader,
        CancellationToken cancellationToken)
    {
        var selectedFields = context.GetSelections((ObjectType)context.Selection.Field.Type);
        if (selectedFields.Count == 1 && selectedFields[0].Field.Name == "id")
        {
            return new ProductDocument(product.TemplateId);
        }
        return loader.LoadAsync(product.ProductTemplateId, cancellationToken);
    }
}
Pascal Senn
  • 1,712
  • 11
  • 20
  • Thanks, this is exactly what I want in part one. In the second I mean, that I would like to get from MongoDB only expected fields. Let's consider that my product template consists of 50 fields. I would like to get only 2 of this fields, but each time I get whole document with 48 not used properties. – Radek Feb 15 '22 at 09:43