2

I am attempting to get the names of all categories that a product belongs to in Commercetools platform.

I can get the unique ID of each category tied to a product through the following call:

final ProductProjectionQuery query = ProductProjectionQuery.ofCurrent();
    ProductProjectionQuery q = query.withLimit(450);

    try {
        PagedQueryResult<io.sphere.sdk.products.ProductProjection> pagedQueryResult = client.execute(q).toCompletableFuture().get();
        List<io.sphere.sdk.products.ProductProjection> products = pagedQueryResult.getResults();

        //createDocument(products.get(0).getMasterVariant(), request);

        for (io.sphere.sdk.products.ProductProjection product : products) {
            String categoryId = product.getCategories().iterator().next().getId();
            //createDocument(product.getMasterVariant(), request);
        }
    }

Though once I have the categoryId, I am unsure of how to access the category name. I thought that the obj property might allow me to drill down into the category, but the obj variable always seems to be null.

Jude Niroshan
  • 4,280
  • 8
  • 40
  • 62
jaikarve
  • 21
  • 1

1 Answers1

4

The obj variable is null because you have not expanded the reference. Unless you explicitly request it, all references will be empty to improve performance. In order to expand it, you can use this code:

// Query products
final ProductProjectionQuery query = ProductProjectionQuery.ofCurrent()
        .withExpansionPaths(product -> product.categories()) // Request to expand categories
        .withLimit(450);
final List<ProductProjection> products = client.execute(query).toCompletableFuture().join().getResults();

for (ProductProjection product : products) {
    final List<LocalizedString> categoryLocalizedNames = product.getCategories().stream()
            .map(categoryRef -> categoryRef.getObj().getName())
            .collect(toList());
    // Do something with categoryLocalizedNames
}

But I strongly recommend you to cache the categories in a CategoryTree instance and grab the name from it, because otherwise the performance will be quite affected by expanding all categories of each product. Here is the code:

// Query all categories and put them in a CategoryTree
final CategoryQuery queryAllCategories = CategoryQuery.of().withLimit(500);
final List<Category> allCategories = client.execute(queryAllCategories).toCompletableFuture().join().getResults();
final CategoryTree categoryTree = CategoryTree.of(allCategories);

// Query products
final ProductProjectionQuery query = ProductProjectionQuery.ofCurrent().withLimit(500);
final List<ProductProjection> products = client.execute(query).toCompletableFuture().join().getResults();

for (ProductProjection product : products) {
    final List<LocalizedString> categoryLocalizedNames = new ArrayList<>();
    product.getCategories().forEach(categoryRef -> {
        final Optional<Category> categoryOpt = categoryTree.findById(categoryRef.getId());
        if (categoryOpt.isPresent()) {
            categoryLocalizedNames.add(categoryOpt.get().getName());
        }
    });
    // Do something with categoryLocalizedNames
}

Of course that means you also have to find a solution to invalidate the cached categories when they change.

Laura Luiz
  • 41
  • 2
  • Thanks Laura! Exactly what I was looking for. Can you point me to the area in the documentation that speaks to reference expansion? – jaikarve Jan 05 '16 at 13:30
  • http://dev.commercetools.com/http-api.html#reference-expansion and http://sphereio.github.io/sphere-jvm-sdk/javadoc/v1.0.0-M24/io/sphere/sdk/models/Reference.html#getObj-- (documentation since M24) and http://sphereio.github.io/sphere-jvm-sdk/javadoc/v1.0.0-M24/io/sphere/sdk/meta/QueryDocumentation.html#reference-expansion – Schleichardt Jan 05 '16 at 22:37