How do I get getorgchart children into multiple columns - getorgchart

How do I get children of the parent to be in two columns? They are all horizontal. We have too many people with one direct report. I've searched the demos and could not find anything.

You can use mixed hierarchy
Here is an example
var orgChart = new getOrgChart(peopleElement, {
primaryFields: ["name", "title", "phone", "mail"],
photoFields: ["image"],
expandToLevel: 100,
layout: getOrgChart.MIXED_HIERARCHY_RIGHT_LINKS
});
also a demo page: http://www.getorgchart.com/Demos/Mixed-Hierarchy

Related

Best practices for structuring hierarchical/classified data in mongodb

Summary:
I am building my first large scale full stack application(MERN stack) that is trying to mimic a large scale clothing store. Each article of clothing has many 'tags' that represent its features, top/bottom/accessory/shoes/ect, and subcategories, for example on top there is shirt/outerwear/sweatshirt/etc, and sub-sub-categories within it, for example on shirt there is blouse/t-shirt/etc. Each article has tags for primary colors, hemline, pockets, technical features, the list goes on.
Main question:
how should I best organize the data in mongodb with mongoose schemas in order for it to be quickly searchable when I plan on having 50,000 or more articles? And genuinely curious, how do large clothing retailers typically design databases to be easily searchable by customers when items have so many identifying features?
Things I have tried or thought of:
On the mongoDB website there is a recommendation to use a tree structure with child references. here is the link: https://docs.mongodb.com/manual/tutorial/model-tree-structures-with-child-references/ I like this idea but I read here: https://developer.mongodb.com/article/mongodb-schema-design-best-practices/ that when storing over a few thousand pieces of data, using object ID references is no longer sufficient, and could create issues because of datalimits.
Further, each clothing item would fall into many different parts of the tree. For example it could be a blouse so it would be in the blouse "leaf" of the tree, and then if its blue, it would be in the blue "leaf" of the tree, and if it is sustainably sourced, it would fall into that "leaf" of the tree as well. Considering this, a tree like data structure seems not the right way to go. It would be storing the same ObjectID in many different leaves.
My other idea was to store the article information (description, price, and picture) seperate from the tagging/hierarchical information. Then each tagging object would have a ObjectID reference to the item. This way I could take advantage of the propogate method of mongoose if I wanted to collect that information.
I also created part of the large tree structure as a proof of concept for a design idea I had, and this is only for the front end right now, but this also creates bad searches cause they would look like taxonomy[0].options[0].options[0].options[0].title to get to 'blouse'. Which from my classes doesnt seem like a good way to make the code readable. This is only a snippet of a long long branching object. I was going to try to make this a mongoose schema. But its a lot of work and I wanna make sure that I do it well.
const taxonomy = [
{
title: 'Category',
selected: false,
options: [
{
title: 'top',
selected: false,
options: [
{
title: 'Shirt',
selected: false,
options: [
{
title: 'Blouse',
selected: false,
},
{
title: 'polo',
selected: false,
},
{
title: 'button down',
selected: false,
},
],
},
{
title: 'T-Shirt',
selected: false,
},
{
title: 'Sweater',
selected: false,
},
{
title: 'Sweatshirt and hoodie',
selected: false,
},
],
},
Moving forward:
I am not looking for a perfect answer, but I am sure that someone has tackled this issue before (all big businesses that sell lots of categorized products have) If someone could just point me in the right direction, for example, give me some terms to google, some articles to read, or some videos to watch, that would be great.
thank you for any direction you can provide.
MongoDB is a document based database. Each record in a collection is a document, and every document should be self-contained (it should contain all information that you need inside it).
The best practice would be to create one collection for each logical whole that you can think of. This is the best practice when you have documents with a lot of data, because it is scalable.
For example, you should create Collections for: Products, Subproducts, Categories, Items, Providers, Discounts...
Now, when you creating Schemas, instead of creating nested structure, you can just store a reference of one collection document as a property of another collection document.
NOTE: The maximum document size is 16 megabytes.
BAD PRACTICE
Let us first see what would be the bad practice. Consider this structure:
Product = {
"name": "Product_name",
"sub_products": [{
"sub_product_name": "Subpoduct_name_1",
"sub_product_description": "Description",
"items": [{
"item_name": "item_name_1",
"item_desciption": "Description",
"discounts": [{
"discount_name": "Discount_1",
"percentage": 25
}]
},
{
"item_name": "item_name_2",
"item_desciption": "Description",
"discounts": [{
"discount_name": "Discount_1",
"percentage": 25
},
{
"discount_name": "Discount_2",
"percentage": 50
}]
},
]
},
...
]
}
Here product document has sub_products property which is an array of sub_products. Each sub_product has items, and each item has discounts. As you can see, because of this nested structure, the maximum document size would be quickly exceeded.
GOOD PRACTICE
Consider this structure:
Product = {
"name": "Product_name",
"sub_products": [
'sub_product_1_id',
'sub_product_2_id',
'sub_product_3_id',
'sub_product_4_id',
'sub_product_5_id',
...
]
}
Subproduct = {
"id": "sub_product_1_id",
"sub_product_name": "Subroduct_name",
"sub_product_description": "Description",
"items": [
'item_1_id',
'item_2_id',
'item_3_id',
'item_4_id',
'item_5_id',
...
]
}
Item = {
"id": "item_1_id",
"item_name": "item_name_1",
"item_desciption": "Description",
"items": [
'discount_1_id',
'discount_2_id',
'discount_3_id',
'discount_4_id',
'discount_5_id',
...
]
}
Discount = {
"id": "discount_1_id",
"discount_name": "Discount_1",
"percentage": 25
}
Now, you have collection for each logical whole and you are just storing a reference of one collection document as a property of another collection document.
Now you can use one of the best features of the Mongoose that is called population. If you store a reference of one collection document as a property of another collection document, when performing querying of the database, Mongoose will replace references with the actual documents.

Algolia Instantsearch with Multiple Indices and Multiple Pagination Widgets

I have implemented instantsearch.js with 1 search input and multiple indices, and multiple stats/pagination widgets. Everything seems to be working correctly except for the pagination widgets.
Here is a codepen https://codepen.io/flrrrhoffpauir/pen/EEpWre
collections.addWidget(
instantsearch.widgets.pagination({
container: '#collections-search-pagination',
showFirstLast: false,
labels: {
next: '>',
previous: '<',
},
cssClasses: {
root: 'search-pagination'
}
})
}
search.addWidget(
instantsearch.widgets.pagination({
container: '#stories-search-pagination',
showFirstLast: false,
labels: {
next: '>',
previous: '<',
},
cssClasses: {
root: 'search-pagination'
}
})
}
If you search for ‘martin’ and then click the Stories tab, you can see the results and that the pagination is working. If you now click the Collections tab, you can see that the pagination widget has the correct number of pages based on how many results were returned according to the stats widget, but then you click to go to page 2, you are just scrolled to the top of the page and it doesn’t load the page 2 data.
How can I get two or more pagination widgets on the page at once that both work correctly?
This is what I went off of to create the multiple index search, but they don't cover multiple pagination widgets: https://jsfiddle.net/j9nwpz34/49/
The searchFunction implementation should transfer all the information that needs to be synchronized. For example, in your case you have a pagination widget that you want to sync across instances of InstantSearch, so you want to transfer the pagination property on top of the query parameter.
var search = instantsearch(
{
/* appId: '',
apiKey: '',
indexName: 'movies',*/
searchFunction: function(helper) {
var query = movies.helper.state.query;
var page = movies.helper.state.page;
products.helper.setQuery(query);
products.helper.setPage(page)
products.helper.search();
helper.search();
},
searchParameters: {
hitsPerPage: 3
}
});
I've modified the JSFiddle to match your need. You can learn more about this state by going to the JS Helper documentation (internal state management of InstantSearch.js).
Update based on the jsFiddle provided:
The rest of the example still holds. However, one thing to note is that if you make a modification in the helper, it will reset the page. In the provided fiddle, you do such a change in the collections searchFunction. You will always set the query, which will always reset the page to 0. Hence the bug.
Here is a fixed fiddle

AEM CQ- nested multifield component, the nested fields starting with 2 text boxes by default

I am using AEM 6.1, building a nested multifield component in classic. However, I want the nested multifield (the one inside) to start with 2 text boxes and at every addition, it needs to add 2 more.
I am using the nested multifield implementation from
https://helpx.adobe.com/experience-manager/using/nested_multifield.html
Has anyone tried this? Please do let me know
Thanks!
Looking at the adobe article you referenced: https://helpx.adobe.com/experience-manager/using/nested_multifield.html
If you want the inner multifield to have 2 fields instead of one, you have to change the multifield's fieldConfig from a text field:
fieldConfig: {
"xtype" : "textfield",
allowBlank: false,
},
to a composite field:
fieldConfig: {
"xtype" : "cq.compositefield",
"items": [
{ "xtype" : "textfield", allowBlank: false},
{ "xtype" : "textfield", allowBlank: false}
]
},
you are also going to likely have to update the updateHidden function to make sure you capture all the information from the new composite field.
References:
AEM 6.1 widget api for more information: https://docs.adobe.com/docs/en/aem/6-1/ref/widgets-api/index.html
multifield doc: https://docs.adobe.com/docs/en/aem/6-1/ref/widgets-api/index.html?class=CQ.form.MultiField
compositeField doc: https://docs.adobe.com/docs/en/aem/6-1/ref/widgets-api/index.html?class=CQ.form.CompositeField

RedQueryBuilder - recursive query

The issue is a self referencing schema such as employee has a supervisor that is an employee. This is tracked with a FK of supervisor_id in the employees table. The FKS is described below:
"fks": [
{
"referencedTableName": "employees",
"name": "supervisor_id_fks",
"label": "Supervisor",
"foreignKeyNames": [
"supervisor_id"
],
"referencedKeyNames": [
"id"
],
"reverseLabel": "Subordinate"
}
Once deployed, the FKS association and the reverse are available in the select options, however, these items are not selectable. Please let me know if there is something I am missing.
I'm afraid it is a bug/missing feature.
There is code to unravel joins when you get back to the same join table.
Please could you raise a ticket:
https://github.com/salk31/RedQueryBuilder/issues
?
Any more background to your use case would be helpful. e.g. Do you only ever want/need the user to go one level deep?

How should I model my MongoDB collection for nested documents?

I'm managing a MongoDB database for a building products store. The most immediate collection is products, right?
There are quite several products, however they all belong to one among a set of 5-8 categories and then to one subcatefory among a small set of subcategories.
For example:
-Electrical
*Wires
p1
p2
..
*Tools
p5
pn
..
*Sockets
p11
p23
..
-Plumber
*Pipes
..
*Tools
..
PVC
..
I will use Angular at web site client side to show whole products catalog, I think about AJAX for querying the right subset of products I want.
Then, I wonder whether I should manage one only collection like:
{
MainCategory1: {
SubCategory1: {
{},{},{},{},{},{},{}
}
SubCategory2: {
{},{},{},{},{},{},{}
}
SubCategoryn: {
{},{},{},{},{},{},{}
}
},
MainCategory2: {
SubCategory1: {
{},{},{},{},{},{},{}
}
SubCategory2: {
{},{},{},{},{},{},{}
}
SubCategoryn: {
{},{},{},{},{},{},{}
}
},
MainCategoryn: {
SubCategory1: {
{},{},{},{},{},{},{}
}
SubCategory2: {
{},{},{},{},{},{},{}
}
SubCategoryn: {
{},{},{},{},{},{},{}
}
}
}
Or a single collection per each category. The number of documents might not be higher than 500. However I care about a balance for:
quick DB answer,
easy server side DB querying, and
client-side Angular code for rendering results to html.
I'm using mongodb node.js module, not Mongoose now.
What CRUD operations will I do?
Inserts of products, I'd also like to have a way to obtain autogenerated ids (maybe sequential) per each new register. However, as it might seem natural I wouldn't offer the _id to the user.
Querying the whole documents set of a subcategory. Maybe just obtaining a few attributes at first.
Querying whole or a specific subset of attributes of a document (product) in particular.
Modifying a product's attributes values.
I agree client side should get the easiest result to render. However, to nest categories into products is still a bad idea. The trade off is once you want to change, for example, the name of a category, it will be a disaster. And if you think about the possible usecases, for example:
list all categories
find all subcategories of a certain category
find all products in a certain category
You'll find it hard to do these stuff with your data structure.
I had same situation in my current project. So here's what I do for your reference.
First, categories should be in a separate collection. DON'T nest categories into each other, as it will complicate the procedure to find all subcategories. The traditional way for finding all subcategories is to maintain an idPath property. For example, your categories are divided into 3 levels:
{
_id: 100,
name: "level1 category"
parentId: 0, // means it's the top category
idPath: "0-100"
}
{
_id: 101,
name: "level2 category"
parentId: 100,
idPath: "0-100-101"
}
{
_id: 102,
name: "level3 category"
parentId: 101,
idPath: "0-100-101-102"
}
Note with idPath, parentId is not necessary anymore. It's for you to understand the structure easier.
Once you need to find all subcategories of category 100, simply do the query:
db.collection("category").find({_id: /^0-100-/}, function(err, doc) {
// whatever you want to do
})
With category stored in a separate collection, in your product you'll need to reference them by _id, just like when we use RDBMS. For example:
{
... // other fields of product
categories: [100, 101, 102, ...]
}
Now if you want to find all products in a certain category:
db.collection("category").find({_id: new RegExp("/^" + idPath + "-/"}, function(err, categories) {
var cateIds = _.pluck(categories, "_id"); // I'm using underscore to pluck category ids
db.collection("product").find({categories: { $in: cateIds }}, function(err, products) {
// products are here
}
})
Fortunately, category collection is usually very small, with only hundreds of records inside (or thousands). And it doesn't varies a lot. So you can always store a live copy of categories inside memory, and it can be constructed as nested objects like:
[{
id: 100,
name: "level 1 category",
... // other fields
subcategories: [{
id: 101,
... // other fields
subcategories: [...]
}, {
id: 103,
... // other fields
subcategories: [...]
},
...]
}, {
// another top1 category
}, ...]
You may want to refresh this copy every several hours, so:
setTimeout(3600000, function() {
// refresh your memory copy of categories.
});
That's all I get in mind right now. Hope it helps.
EDIT:
to provide int ID for each user, $inc and findAndModify is very useful. you may have a idSeed collection:
{
_id: ...,
seedValue: 1,
forCollection: "user"
}
When you want to get an unique ID:
db.collection("idSeed").findAndModify({forCollection: "user"}, {}, {$inc: {seedValue: 1}}, {}, function(err, doc) {
var newId = doc.seedValue;
});
The findAndModify is an atomic operator provided by mongodb. It will guarantee thread safety. and the find and modify actually happens in a "transaction".
2nd question is in my answer already.
query subsets of properties is described with mongodb Manual. NodeJS API is almost the same. Read the document of projection parameter.
update subsets is also supported by $set of mongodb operator.

Resources