0

In my project I am now needing to obtain the variant of the product from the variantKey, but I have not found any method in the JVM SDK to do it. I tried to do it using the ProductByKeyGet method, but I only get the product if the value corresponds to the root key of the product, but if the value corresponds to the variantKey it does not return anything to me.

Does anyone know any way to get the variant from its VariantKey?

Thanks in advance. Miguel de la Hoz

MiguelHoz
  • 49
  • 6

2 Answers2

3

For that you will need to use the Product Projection endpoint, where you can query for products which have either a variant "OR" master variant with the key you desire. Through the JVM SDK, you can achieve that by doing the following:

  1. Build a QueryPredicate<EmbeddedProductVariantQueryModel> for the key you desire :

    final String myKey = "foo";
    final QueryPredicate<EmbeddedProductVariantQueryModel> queryPredicate =
        QueryPredicate.of("key=\"" + myKey + "\"");
    
  2. Build a Function<ProductProjectionQueryModel, QueryPredicate<ProductProjection>> to query for the master variant:

    final Function<ProductProjectionQueryModel, QueryPredicate<ProductProjection>> mvPredicateFunction = productQueryModel ->
        productQueryModel.masterVariant().where(queryPredicate);
    
  3. Build a Function<ProductProjectionQueryModel, QueryPredicate<ProductProjection>> to query for the rest of the variants:

    final Function<ProductProjectionQueryModel, QueryPredicate<ProductProjection>> variantsPredicateFunction = productQueryModel ->
        productQueryModel.variants().where(queryPredicate);
    
  4. Combine both predicates with a semantic OR operator to build the ProductProjectionQuery (in this case on the staged projection):

    final ProductProjectionQuery query = ProductProjectionQuery.ofStaged()
                                                               .withPredicates(productQueryModel -> mvPredicateFunction
                                                                   .apply(productQueryModel)
                                                                   .or(variantsPredicateFunction.apply(productQueryModel)));
    
  5. Execute the request:

    final PagedQueryResult<ProductProjection> requestStage = sphereClient.executeBlocking(query);
    
  6. Since variant keys are unique, you should be expecting to yield one resulting product projection, if any:

    final Optional<ProductProjection> optionalProductProjection = requestStage.head();
    
  7. Traverse all (including the master variant) variants of the resultant product projection to fetch the matching variant with such key:

    final Optional<ProductVariant> optionalVariant = optionalProductProjection.flatMap(
        productProjection -> productProjection.getAllVariants().stream()
                                              .filter(productVariant -> myKey.equals(productVariant.getKey()))
                                              .findFirst());
    

Update: Steps 1-4 can also be simplified to:

    final String myKey = "foo";
    final QueryPredicate<ProductProjection> productProjectionQueryPredicate = QueryPredicate
        .of("masterVariant(key = \"" +  myKey + "\") OR variants(key = \"" + myKey + "\")");
    final ProductProjectionQuery query = ProductProjectionQuery.ofStaged().withPredicates(
        productProjectionQueryPredicate);
Hesham Massoud
  • 1,550
  • 1
  • 11
  • 17
  • The search endpoint shall be used for product variant related product discovery, this is why the DSL for the query endpoint does not support it. Use http://commercetools.github.io/commercetools-jvm-sdk/apidocs/io/sphere/sdk/products/search/ProductProjectionSearch.html instead – Dalek Feb 07 '18 at 09:00
  • @Dalek well, the search endpoint could also be used for that. But I would say it depends on the use case. It's important to note that the Product Projection Search endpoint provides an [Eventual Consistency](http://dev.commercetools.com/http-api.html#eventual-consistency) guarantee, which means it should not be used in the context of a data sync or a product display page, where the user needs to add the product to cart, since the data might not be up to date. – Hesham Massoud Feb 07 '18 at 09:22
  • Thanks @Dalek. I've played with your code, but using the Product object instead of the ProductProjection because what I need is to obtain the product to update it later. I don't need to show the product at any time. Thank again – MiguelHoz Mar 06 '18 at 09:42
3

Today we released version 1.29.0 of our JVM SDK - where we added the missing support for querying product variants by key (see https://github.com/commercetools/commercetools-jvm-sdk/issues/1679). With this version you can then write the query in a typesafe fashion:

String myKey = "foo";
ProductProjectionType projectionType = ProductProjectionType.CURRENT;

ProductProjectionQuery query =
    ProductProjectionQuery.of(projectionType)
         .withPredicates(product -> product.allVariants()
            .where(variant -> variant.key().is(myKey)));

Hope this helps!