I'm taking my first dive into noSQL (AWS DynamoDB) and writing a nodejs app which will maintain a product catalog. The product catalog has 2 types of item - Product and Category.
Products can appear in multiple categories. I'm really struggling to find a source of information on how best to approach this, I think using a query would be the right solution but ideally both the solution and the data would be elegant.
At present my products look a bit like:
{
"productId": 12930,
"productCode": "DIHA",
"name": "6 Bottle Beer Pack",
"onSale": true,
"newItem": false,
"relatedItems": [1240, 1201, 4508, 55067],
"categoryIds": [1201, 1202, 1203, 1204]
}
The aim is to be able to query products in a category e.g. 1203 and then filter by facets such as onSale & newItem.
I have seen an example whereby they flatten the categories like so
"category_1": 1201,
"category_2": 1202,
"category_3": 1203,
"category_4": 1204,
...
But something about that approach doesn't sit right with me (inelegant?)
I have played with using normalized tables e.g. CategoryProduct which lists the categoryIds with their related productIds.
{
1201: [12930, 12931, 12932, 12933 ...],
1202: [12930, 12678, 12679, 12680 ...],
1203: [12930, 12500, 12501],
1204: [12930, 12931],
...
}
But if my understanding is right then this would be quite resource heavy and lead to multiple reads just to acquire the products to filter against
Does anyone know of any tutorials or resources where filtering an entire catalog by categories or tags exists? I feel like I've trawled Google/GitHub/stackoverflow and not yet seen an example to go on.
I'll be eternally grateful if someone could share their knowledge/resources with me.
Related
I have the following JSON data.
{
"partners": [
{
"logo": "school-of-bookkeeping.png",
"title": "Schoolofbook<br class='d-none d-md-inline-block'/>keeping.com",
"websiteURL":"https://www.schoolofbookkeeping.com",
"getInTouchURL":"https://www.schoolofbookkeeping.com",
"location":"Santa Monical, CA, US",
"servicesCategories":["Consulting Services","Webgility Setup"],
"accountingSoftware":["QuickBooks Online","QuickBooks Enterprise","QuickBooks Point of Sale"],
"onlineStore":["Magento","Shopify","WooCommerce"],
"marketplace":["Amazon","eBay","Etsy"],
"description": "Teaching Businesses and Accounting Professionals the ins and outs of ecommerce.",
"longDescription":"<p class='fs-16 lh-1-5'>Let's face it; ecommerce is hard. From tracking inventory, sales tax requirements, shipping fulfillment, and general bookkeeping, keeping pace with all the requirements and business workflows is difficult. That's why we have partnered with Webgility to create a learning resource to provide small and medium-sized businesses a seamless and path from setup to implementation, so the accounting is done so that can focus on running your business, rather than your business, rather than running yourself ragged.</p><p class='fs-16 lh-1-5'>Our lifelong learners are here for hire so you can be set up for success and have a trusted advisor to guide you through setup to implementation.</p>",
"servicesWeProvide": "<p class='fs-16 lh-1-5'>Website creation to e-commerce implementation.</p>",
"featured": false,
"partnerType": "Certified",
"link": "school-of-bookkeeping",
"customClass": "school-of-bookkeeping"
},
{
"logo": "danwidth.png",
"title": "Danwidth",
"websiteURL":"https://www.danwidth.com",
"getInTouchURL":"https://completebusinessgroup.com/danwidth/",
"location":"Tucson, AZ, US",
"servicesCategories":["Consulting Services","Webgility Setup"],
"accountingSoftware":["QuickBooks Online","QuickBooks Enterprise","QuickBooks Point of Sale"],
"onlineStore":["Magento","Shopify","WooCommerce"],
"marketplace":["Amazon","eBay","Etsy"],
"description": "Put your ecommerce bookkeeping on cruise control.",
"longDescription":"<p class='fs-16 lh-1-5'>I don't want to be your bookkeeper. I transform businesses through technology by creating automagic workflows that allow your bookkeeping to be handled \"by accident.\" Imagine entering data once, or not at all, and your bookkeeping is done for you. Specializing in brick and mortar retail and ecommerce, I will set up your services to integrate so that your accounting and bookkeeping is done for you as a result of you simply running your business. We work with a host of solution providers that all integrate into your accounting platform that will enable you to make informed business decisions in real-time.</p><p class='fs-16 lh-1-5'>My expertise is unparalleled across all of Intuit's Small business platforms. Online or Desktop, including Point of Sale, if it can be done in QuickBooks, I know how to make it happen. In addition, we partner with other business services to increase your revenue, decrease your expenses, and widen your online presence.</p>",
"servicesWeProvide": "<p class='fs-16 lh-1-5'>End-to-end services from website creation, digital marketing, ecommerce platform to bookkeeping, payroll service setup, and support.</p>",
"featured": false,
"partnerType": "Certified",
"link": "danwidth",
"customClass": ""
}
]
}
How can I filter this on the basis of servicesCategories, accountingSoftware, onlineStore, marketplace, and partnerType?
I want to filter data with $.getJSON() method with on change select box value.
That depends on how you want to go about filtering. There are a few different ways to accomplish this, here is one function that allows you to pass in the key you want to filter on and an array of values to filter by:
let filterBy = (list, keyToFilter, filters) => {
// Allow a string to be passed in
if(!Array.isArray(filters)) filters = [filters];
return list.filter(item => {
let values = item[keyToFilter];
// Check if the filter exists
if(!values) return false;
// For items that aren't arrays, like partnerType
// This makes it compatible with the conditional
// below, where the logic for check happens.
if(!Array.isArray(values)) values = [values];
// Check if array of your filters matches any in list
return filters.some(n => values.includes(n));
}
);
};
Then you can call this on your list like so:
let list = { "partners": [
...
]};
let accountingSoftware = filterBy(list["partners"], "accountingSoftware", ["QuickBooks Online","QuickBooks Enterprise"]);
let partnerType = filterBy(list["partners"], "partnerType", "Certified");
Here is an example if you want to play around with it more, https://repl.it/#BenjaminKnox/filter-json
I am prototyping a Food Ordering app using Dialogflow(Chatbot maker) and got stuck with this problem. Technically, I want to persist the gathered data from an Intent after the user decided to "add more items to their order" and satisfies all the required parameters, which are, (itemName, quantity, [variants], [sauceType], ...).
The chat bot should be able to handle a request which consist of multiple items with their corresponding quantities but I am not sure if it's possible to model a data wherein it consist an array of Entities so, my first thought was to use a persistent Fulfillment using session-based Webhook with our custom Web Service, like for example: foodorder/api/order/123/items/add and 123 being the Session Id. But this approach requires more work and the generated model can be difficult to translate in Dialoflow Console.
The second solution comes into my mind, is to leverage the Intent property called Action and Parameters where we mark the Entity as List, but using this approach, the quantity doesn't get attached to the item itself.
My question is, how can I be able to model a data using Dialogflow that resembles something like below:
{
"givenName": "Dummy User",
"order": [
{
"itemName": "Burger",
"quantity": 2
},
{
"itemName": "6 piece Chicken Nuggets",
"quantity": 1,
"sauceType": "Tangy Barbeque"
},
{
"itemName": "Coke",
"quantity": 1,
"size": "Small"
}
]
}
Turns out what I was looking for was Composite Entities and mark it as a list.
The detailed answer can be found on this link:
https://stackoverflow.com/a/47166123/2304737
I'm new with Angular, Js etc, and have a problem with understanding how should work with nested data. For example:
I have four json files:
categories
subcategories
posts
comments
It's better to have 4 different files like above, or one like this:
{
"id_category":"1",
"name":"business",
"subcategories":{
"id":"1",
"name":"ecommerse",
"posts": {
"id": 1,
"title": "New post"
"comments": {
"id": 1,
"text": "text text text"
}
}
}
Of course it's only an example, but for that example I need to find comment by Id = 1 to get information about which post this comment is related to, which subcategory and category.
Now I have four different files, and services to get data from json files. I can get a specific comment by ID:
getComment(Id: number) {
return this.comments.find(
(comment) =>
comment.id === Id
);
}
ok, fine. But If I want to get information about post, subcategory, and main category for this comment? What should I do?
It depends on what the specific needs of your application are.
With this structure:
{
"id_category":"1",
"name":"business",
"subcategories":{
"id":"1",
"name":"ecommerse",
"posts": {
"id": 1,
"title": "New post"
"comments": {
"id": 1,
"text": "text text text"
}
}
}
You could iterate over Categories and display a list, then allow a user to select a single category, and assign that to var currentCategory.
You could then iterate over currentCategory.subcategories to allow the user to select a subcategory and assign that to var currentSubCategory. You would keep drilling down then into currentSubCategory.posts, allow the user to select a post, assign that to var currentPost and then iterate over that to display currentPost.comments.
If you're fetching from a database in order to allow the user to drill down into the data for display only, then something like this would work.
If you're maintaining data in JSON files, then I would look at something like JSON Server https://github.com/typicode/json-server
If you're building something more substantial and you have a database backend, make use of the database and don't try to recreate that functionality in your JSON, use JSON as a transport for the data, but don't try to replicate entire tables or complex data structures in your front end code, just fetch what you need as you need it, as that will make for a much more stable and scalable application, and will also make it easier for you do fetch and update data in small manageable chunks.
For mocking a data backend using JSON, consider json-server
https://www.npmjs.com/package/json-server
I've been using NeDB as a persistent data storage model in my Electron/Angular application. The setup of this data works perfectly for the main purpose of my application. I show everything from table "0" and when the use clicks on an options it takes them to all items from table "1" that have a "foreign" that matches the "key" from the selected item from table "0". Like any other 1:n relational data.
I want to display the objects in an accordion like fashion for my users to be able to interact with the relationships. I want to be able to do this recursively, but cannot seem to wrap my head around it.
A chunk from my flat JSON file is this:
{"_id":"000000","type":"dc","table":"0","key":"A","cat":"CAD Assessment","foreign":"A"}
{"_id":"000002","type":"dc","table":"1","key":"1","cat":"Coronary angiography with or without left heart catheterization and left ventriculography","foreign":"A"}
{"_id":"000005","type":"dc","table":"2","key":"1.1","cat":"Suspected or known ACS","foreign":"1"}
{"_id":"000006","type":"dc","table":"2","key":"1.2","cat":"Suspected CAD: No prior noninvasive stress imaging (no prior PCI, CABG, or angiogram showing >=50% angiographic stenosis)","foreign":"1"}
And I want it to look like this:
{
"_id":"000000",
"type":"dc",
"table":"0",
"key":"A",
"cat":"CAD Assessment",
"foreign": [
{
"_id":"000002",
"type":"dc",
"table":"1",
"key":"1",
"cat":"Coronary angiography with or without left heart catheterization and left ventriculography"
"foreign": [
{
"_id":"000005",
"type":"dc",
"table":"2",
"key":"1.1",
"cat":"Suspected or known ACS",
"foreign":"1"
},
{
"_id":"000006",
"type":"dc",
"table":"2",
"key":"1.2",
"cat":"Suspected CAD: No prior noninvasive stress imaging (no prior PCI, CABG, or angiogram showing >=50% angiographic stenosis)",
"foreign":"1"
}
]
}
]
}
Is this even a possible thing? I'm hoping somebody with a lot more experience can point me in the right direction here. I'm ready to stop banging my head against the wall.
Before I start, please don't tell me to use SQL. This is a small problem in a bigger context and I can't and don't want to use a relational database here. I know the problem is pretty easy to solve in SQL.
There are three types of documents:
Players
Teams
Sponsors
Teams belong to one sponsor but have many players. A player can be in multiple teams and a sponsor can have multiple teams.
Players 1 --- N Teams N --- 1 Sponsors
I put the player document ids into the Teams document in an array:
players: ["payer1","player2",...]
Now I want all (distinct, only named once) sponsors for a specific player:
Player1: Sponsor1, Sponsor2, Sponsor3,...
It's a bit like the n-n example in the CouchDB Wiki, but since there are multiple keys in the team-players, that doesn't really work.
I created a gist with example data..
Any idea how to write the MapReduce function to get to this result?
The closest I got, but shows sponsors multiple times, with group level 1:
function(doc) {
if(doc.type == "team")
emit(doc.players,doc.sponsor);
}
function(keys, values) {
return (values);
}
You are close with your view, here it is modified slightly:
"playerSponsers": {
"map": "function(doc) {
if(doc.type == "team" && doc.players) {
for (i in doc.players) {
emit([doc.players[i], doc.sponsor],1);
}
}
}",
"reduce": "_sum"
}
And here is the query:
http://localhost:5984/test/_design/sports/_view/playerSponsors?group=true&group_level=2
You will get results like this:
{"rows":[
{"key":["Player1","Sponsor1"],"value":1},
{"key":["Player1","Sponsor2"],"value":1},
{"key":["Player1","Sponsor3"],"value":1},
{"key":["Player2","Sponsor1"],"value":1},
{"key":["Player2","Sponsor2"],"value":2},
{"key":["Player2","Sponsor3"],"value":1}
]}
If you want to get the sponsors for just one player, you can query like this
http://localhost:81/test/_design/sports/_view/playerSponsors?group=true&group_level=2&startkey=[%22Player1%22]&endkey=[%22Player1%22,{}]