My goal is to create an e-commerce website where customers can see related products on any product page (similar to amazon.com).
I have no idea how to get started with such a daunting task. From my research, my guess is to do the following:
Create a Category
kind:
class Category(ndb.Model):
name = ndb.StringProperty()
Whenever a product is created, associate it with a Category via an ancestral relationship:
parent_category = ndb.Key("Category", "Books")
new_product = Product(
title="Coding Horrors Book",
parent=parent_category).put()
Now, on each product page, I can create a query to return a list of books as related products.
I have some concerns with this approach:
Firstly, this doesn't feel like a solid approach.
How do I specify the hierarchical relationship between product categories? For example, if we have two product categories, "AngularJS", "VueJS", how do we specify that these two categories are somehow related?
First, to clarify, the entity ancestry is not mandatory for establishing relationships (and it has some disadvantages), see Can you help me understand the nbd Key Class Documentation or rather ancestor relationship?. and related Ancestor relation in datastore
You'll need to consider Balancing Strong and Eventual Consistency with Google Cloud Datastore.
The rest of the answer assumes no entity ancestry is used.
To associate a product to a category (or several of them, if you want, using repeated properties) you can have:
class Product(ndb.Model):
name = ndb.StringProperty()
category = ndb.KeyProperty(kind='Category', repeated=True)
category = ndb.Key("Category", "Books")
new_product = Product(title="Coding Horrors Book",
category=[category]).put()
This approach has a scalability issue: if a product falls into many categories, updating the category list becomes increasingly slower (the entire entity, progressively growing, needs to be re-written every time) and, if the property is indexed, it is sensitive to the exploding indexes problem.
This can be avoided by storing product-category relationships as separate entities:
class ProductCategory(ndb.Model):
product = ndb.KeyProperty(kind='Product')
category = ndb.KeyProperty(kind='Category')
Scales a lot better, but in this case you'll need a ProductCategory
query to determine the keys of related category entities for a product, followed by key lookups to get the details of those categories, something along these lines:
category_keys = ProductCategory.query(ProductCategory.product == product_key) \
.fetch(keys_only=True, limit=500)
if category_keys:
categories = ndb.get_multi(category_keys)
logging.info('product %s categories: %s' \
% (product.title, ','.join([c.name for c in categories])))