As Manuel said, you really need to model your data to solve your particular scenarios, that is what your use-cases are asking you to do. This often results in de-normalization of data but the exact de-normalization of the data is application specific.
For example, if your use-case required you to be able to determine the quantities of a particular product in a particular store, you might have one Set which has a compound key containing the storeId and productId with a Bin holding the inventory count in that store. This would make it a very fast lookup.
However, if you want to know which stores have particular products, and which products are in which stores, you might model it closer to how Manuel says. With NoSQL databases, itās best to approach your modeling from the use-case perspective rather than āhow do I form a general data model to store my information, Iāll work out how to address the use cases laterā.
If you want to model the information along the lines Manuel has suggested, this is a little code snippet (using the Java client) which might help:
// Create a new store, and give it a couple of products
List<String> productIds = Arrays.asList("prod1234", "prod1235");
String storeId = "store00314";
Bin name = new Bin("name", "a Store");
Bin products = new Bin("productIds", productIds);
Key storeKey = new Key("test", "store", storeId);
client.put(null, storeKey, name, products );
// The store now contains the products, we have to make sure we tell the products
// that they're in the store too. Note the use of the generationPolicy to make sure
// we don't bump into concurrency issues.
for (String productId : productIds) {
Key productKey = new Key("test", "product", productId);
Record thisProduct = client.get(null, productKey);
List<String> storeIds = (List<String>) thisProduct.getValue("stores");
if (!storeIds.contains(storeId)) {
// We have to add it back into this list
storeIds.add(storeId);
// And put it back, ensuring it hasn't been changed in the meantime
WritePolicy writePolicy = new WritePolicy();
writePolicy.generation = thisProduct.generation;
writePolicy.generationPolicy = GenerationPolicy.EXPECT_GEN_EQUAL;
client.put(writePolicy, productKey, new Bin("stores", storeIds));
}
}
Now we can use the query operations to find out information about the products:
// Now see if a given product is in the store
String prodId = "prod1235";
Key theStoreKey = new Key("test", "store", storeId);
// Get the products for the store, in this case this is the only information we want so
// just specify the one bin name.
Record storeRecord = client.get(null, theStoreKey, "productIds");
List<String> storeProductIds = (List<String>) storeRecord.getValue("productIds");
if (storeProductIds.contains(prodId)) {
System.out.println("Store contains product!");
}
Note that Iām using a list here rather than a large list. If youāre storing ids, a list is probably fine for your needs ā you have up to 128kB to play with in a single Record and this is expandable if needed so shouldnāt be a limitation. A Map here would probably work better too, but Iām not sure of your particular use case so I thought the list example might be simpler. If your lists are growing very large you might have a processing impact as you search through them which could be solved by modeling the data differently ā again this depends on your use-cases.
Hope this helps,
Tim