I have an array of data fetched from a database table that uses the adjacency model to build a heirarchy of topics. Each record contains the following fields:
'id' - a unique AI id.
'name' - a display name.
'parent_id' - the id of a parent topic (can be null for root topics)
The array comes from the database un-nested and sorted by id as you would expect. The 'id' field is random and abritary and cannot be relied upon to produce a useful order. I am seeking a way to sort the array using the parent_id so that it is in the correct adjacency order but without the end result being nested into sub arrays. The list would look like below:
RootTopicA
ATopic1
ATopic2
Child1ofATopic2
Child2ofATopic2
ATopic3
RootTopicB
BTopic1
BTopic2
etc.
Any help or a pointer to an example (even in a different language) would be much appreciated.
You can add a field for example sort in which you would store the order of the same ids in the category.
The other solution is to sort them (in SQL) by ORDER BY parent_id, id or combining the two, ORDER BY sort, using JOINs like (not tested):
SELECT object.id, object.sort, parent.id, parent.sort
FROM objects AS object
LEFT JOIN objects AS parent ON object.parent=parent.id
ORDER BY parent.sort, object.sort;
assuming that objects is your table name, the same table is object as the main object, and parent as object that is its parent (you need it to get sort of parent).
Related
I have a list of products, which can have different properties (color, size etc).
Properties are saved in my db as property table in the following form:
While the chosen properties get saved to each individual product in the form of parentid.id, for example this 2nd entry (id 4) has blue color property.
But what I'm trying to achieve now, is to echo these selected values on the product, the same way they are saved, so:
Parent Title - This id (child) or based on example: Color - Blue.
But I can't figure out, how to. I've tried imploding the properties array, but then I only get the last part, so only 2 from 1.2 and echoes Blue. I would need both, 1 and 2 (Color-blue).
It's kind of hard to explain, but if anyone understood at least a bit what I would need and has any idea how this could be done, I would be very grateful for any tips and hints.
Thanks in advance ;)
What you need to do to make this work:
Select your properties from db
Parse them into groups (explode by ',' to work with them one at a time)
Build an array of parent/children by parsing the groups
(ex: groupings = [
parent1 => [child1, child2, etc],
parent2 => [child1, child2, etc],
])
a. loop through each group
b. explode by '.' to get the parent/child pairing
c. put into array
Build your where clause
a. Parents: where (id in (parent1, parent2, etc))
b. Children: (parent = parent AND id IN (child1, child2, etc))
I am trying to find the best way to handle category and sub category. I have 20 category and 50 sub category. Which of these is best way to do so :
Save data in a json file and reading content directly on client side.
Save data in database in single table and using parent id to see the relation and using foreach on result array inside another foreach of same array.
Save data in database in two table, making one sql call to parent category another one call to sub category and using parent id to see the relation and using foreach of sub category array inside another foreach of parent array.
Save data in database in two table, making one sql call to parent category and then inside its foreach making multiple sql calls to database.
I tried to find the best practice to handle categories but couldn't find any article for the same.
The solution depends purely on how complex your database schema and other entities relate to the categories. And how you intend to read the information.
The json approach would be faster, but has issues when it comes to queries that would require you to link up to category additional information.
Another approach I have used and had good performance is storing all categories in a single table. The relationships are not stored in the main table.
Another table stores the relationships as graph edges. This is quite advantageous if you have cyclic relationships within the categories. Or more than one parent.
The schema would look like :
categories ( id, name )
category_edges ( parent_id, child_id)
I used oqgraph with my implementation to get the relationships queries faster. But that was with MariaDB and not mysql.
Hope this helps.
I would like to store a nested associative array in MySQL. I need this for a nestable navigation menu on my site. There should be no limit to the level of nesting.
I have researched the nested set model and the adjacency list, but am unsure of which to use for my needs.
Ideally, I will be able to query my table in a way that I can reconstruct my associative array in PHP and then use this to construct my navigation menu.
Records may be added / changed / re-ordered, but this will only happen infrequently.
I am looking for an example table structure for MySQL (InnoDB), queries to get and re-order the records, and update, delete and add new records. I am using PDO in PHP so any example code of how to turn the record set into the associative array would also be helpful.
Try the following design:
Column 'BEFORE'
Column 'AFTER'
Column 'NAME'
Column 'ID'
Now, just store ID as required.
Example: The navigation menu might be
A --> B --> C
Just give an ID to each entry in the menu and store it with an unique ID.
Then enter the BEFORE and AFTER values as IDs into the table.
So, for B we have
Entry for B:
BEFORE = ID(C)
AFTER = ID(A)
NAME = 'B'
This can be easily expanded for multiple nested menus.
I would suggest following design for implementing the solution.
Table : Navigation
Columns :
ID (INT NOT NULL IDENTITY),
Description (VARCHAR),
ParentID (INT NULL) - Refer its own table ID column,
AdditionalColulmns..
I have two entities, post and category which is a 1:n relationship.
I have a reference table with two columns, post_id,category_id
The categories table has an id column, a status column and a parent_id column
If a category is a child of another category (n-depth) then it's parent_id is not null.
If a category is online it's status is 1, otherwise it is 0.
What I need to do is find out if a post is visible.
This requires:
Foreach category joined to the post trace up it's tree to the root node (till a category has parent_id == null), if any of those categories have status 0 then that path is considered offline.
If any path is online then the post is considered visible, otherwise it is hidden.
The only way I can think of doing this (as semi-pseudo code) is:
function visible(category_ids){
categories = //select * from categories where id in(category_ids)
online = false
foreach(categories as category){
if(category.status == 0)
continue;
children = //select id from categories where parent_id = category.id
if(children)
online = visible(children)
}
return online
}
categories = //select c.id from categories c join posts_categories pc on pc.category_id = c.id where pc.post_id = post.id
post.online = visible(categories)
But that could end up being a lot of sql queries, is there a better way?
If nested sets are not an option, I know about the following:
If the data is ordered so that children of a parent always follow after it's parent, you can solve this with one database-query over all data by skipping hidden nodes in the output.
This works equally with a sorted nested set, too, the principle has been outlined in this answer however the algorithms about getting the depth do not work and I would suggest a recursive iterator that is able to remove hidden items.
Also if the data is not ordered, you can create a tree structure from the (unsorted) query of all rows like outlined in the answer to Nested array. Third level is disappearing. No recursion needed and you get a structure you can easily output then, I should have covered that for <ul>/<li> html style output in another answer, too.
Answer to How can I convert a series of parent-child relationships into a hierarchical tree?
Answer to How to obtain a nested HTML list from object's array recordset?
A classic database vs memory tradeoff. What you are doing is building a tree with leafs in it. To build the tree you need recursive loop the leafs. Coming from a database there are 2 scenarios:
Build the tree recursive with a query for each leaf. You hold 1 tree in memory. That is what you are doing.
Get a flat structure from the database, and build the tree recursive in memory. You hold a flat tree and the real tree in memory. That is your alternative way.
What is better depends on a lot of things: your hardware (disk access vs memory), the size of the tree to name two.
In an ActiveRecord (CakePHP flavored) setup I have a HasAndBelongsToMany association setup on Videos and Bins: A Bin can store n references to Videos, and Videos can belong to n Bins.
I need to be able to manually set and store the display order of the Videos within a particular Bin (so the client can have his Videos in a particular order within the Bin.) My initial thought is to create a field in Bin that stores an array of Video IDs in the order they need to appear. Is this the most efficient way to handle this?
If so, when I then get the HABTM query result, what is the cleanest/most efficient way to re-order the returned query to match the sorted array of ID's?
The Videos associated with a Bin are returned as an array:
[Video] => Array
(
[0] => Array
(
[id] => 49b2de95-0338-48b9-bc88-01ba35664358
...
)
[1] => Array
(
[id] => 49b1ccad-b770-410e-be46-03a035664358
...
)
Or is there a better way to achieve what I'm trying to do without using HABTM associations?
Thanks in advance -
What to do when HABTM becomes complicated?
By default when saving a HasAndBelongsToMany relationship, Cake will delete all rows on the join table before saving new ones. For example if you have a Club that has 10 Children associated. You then update the Club with 2 children. The Club will only have 2 Children, not 12.
Also note that if you want to add more fields to the join (when it was created or meta information) this is possible with HABTM join tables, but it is important to understand that you have an easy option.
HasAndBelongsToMany between two models is in reality shorthand for three models associated through both a hasMany and a belongsTo association.
Consider this example:
Child hasAndBelongsToMany Club
Another way to look at this is adding a Membership model
Child hasMany Membership
Membership belongsTo Child,
ClubClub hasMany Membership.
These two examples are almost the exact same. They use the same amount and named fields in the database and the same amount of models. The important differences are that the "join" model is named differently and it's behavior is more predictable.
In your example, you need a way to add and remove without editing other users Video links, therefore standard habtm will not suit you very well. Create a model for this "join" similar to the Membership model described above. Further, if you added a weight field, you could use the ordered behavior (that I wrote) to order each set of videos per bin. Then you would use the following fields
id, bin_id, video_id, weight
And set up bin_id as the 'foreign_key' in the behavior configuartion. Good luck
Well I tried to solve just this problem and think I found the simplest solution possible:
When saving a new order of the related models you delete the existing relations and add the new ones in the desired order. This means the ids created run in your sort order and you can simply sort by id to display the order.
public $hasAndBelongsToMany = array(
'Item' => array(
'order' => 'ItemFoldersItem.id ASC, Item.name DESC',
)
);
Pretty simple isn't it?
Don't know about "most efficient" way to implement what you want, that depends on your whole application and what you want to accomplish. I'd just keep in mind that the most simple solution is often the best.
However, I can give you a tip for sorting your Video array! It is fairly easy:
$yourData = Set::sort($yourData, '/Video/id', 'asc');
Take a look at the Set class for more candy. :)