A noob question. I'm putting together my first database and have the following design problem: I have a class which defines a book (e.g. it's title) and a class which defines a page (e.g. it's design).
The table for the class book would look so:
Title | PAGE1 | PAGE2 | PAGE3
Book-One | SAMPLE1-UUID | SAMPLE2-UUID | SAMPLE3-UUID
Book-Two | SAMPLE4-UUID | SAMPLE5-UUID | SAMPLE6-UUID
The table for the class page:
UUID | FONT | CONTENTS etc.
SAMPLE1-UUID | Times | Example
SAMPLE2-UUID | Arial | Example Two
SAMPLE3-UUID | Verdena | Example Three
Now, as each page is unique and can't be re-used in another book, I can't use a many-to-many relationship for Pages. I could use Foreign-Key to link the two tables, i.e. link SAMPLE1-UUID of the Books Table with the SAMPLE1-UUID of the Pages Table. This has the advantage of not creating the same entry twice.
However, I don't like the idea of having a fixed amount of rows for my pages. In the above example for the class Book, I'd have to define a certain set of Pages, like PAGE1, PAGE2, PAGE3, PAGE4, ... PAGE99. Ideally, all I need is a flexible list of pages for my book class, like so:
Name | Pages
Book-One | "SAMPLE1-UUID, SAMPLE2-UUID"
Book-Two | "SAMPLE4-UUID, SAMPLE5-UUID, SAMPLE6-UUID"
Pages would be a simple CharField and its contents would be a list. But then I have the problem that the two tables are not linked anymore and that I'd have to create each entry twice (i.e. I would have to enter SAMPLE1-UUID in both the pages and books table).
Is there another way to design this database? Thanks for any suggestion!
I'll suggest you don't have the pages as columns:
The table for the class book would look so with book only information:
Title | ISBN
Book-One | XXXXXXXXXXXX
Book-Two | YYYYYYYYYYYY
The table for the class page:
BOOKID |PAGE_NUM | FONT | CONTENTS
1 |1 | Times | Example
1 |2 | Arial | Example Two
2 |1 | Verdena | Example Three
Your class design would look something like:
class Book(models.Model):
title = models.CharField(max_length=100)
isbn = models.CharField(max_length=100)
class Page(models.Model):
book = models.ForeignKey(Book)
page_num = models.IntegerField()
font = models.charField(max_length=100)
content = models.TextField()
You can go ahead and have contraints so that a book and page_num does not repeat for instance but this can be a good start.
I would do it like this:
class Book(models.Model):
name=models.CharField(max_length=....)
class Page(models.Model):
book=models.ForeignKey(Book)
number=models.PositiveIntegerField()
I don't understand your book table example: Do you want a column for page1 and an other column for page2? That looks very strange.
You've misunderstood how a foreign key works. It's not a "fixed amount of rows" - just the opposite, in fact.
As guettli shows in his answer, a ForeignKey field is a one-to-many relationship, defined on the "many" side. That is, with the ForeignKey defined on Page pointing at Book, each Page has one Book, but a Book has as many Pages as you like.
So, using the Django ORM, if you have a book object and you want to get all its pages, you just do my_book.page_set.all().
Related
I'm trying to create a database for a frienship website I'm building. I want to store multiple attributes about the user such as gender, education, pets etc.
Solution #1 - User table:
id | age | birth day | City | Gender | Education | fav Pet | fav hobbie. . .
--------------------------------------------------------------------------
0 | 38 | 1985 | New York | Female | University | Dog | Ping Pong
The problem I'm having is the list of attributes goes on and on and right now my user table has 20 something columns.
I feel I could normalize this by creating another table for each attribute see below. However this would create many joins and I'm still left with a lot of columns in the user table.
Solution #2 - User table:
id | age | birth day | City | Gender | Education | fav Pet | fav hobbies
--------------------------------------------------------------------------
0 | 38 | 1985 | New York | 0 | 0 | 0 | 0
Pets table:
id | Pet Type
---------------
0 | Dog
Anyone have any ideas how to approach this problem it feels like both answers are wrong. What is the proper table design for this database?
There is more to this than meets the eye: First of all - if you have tons of attributes, many of which will likely be null for any specific row, and with a very dynamic selection of attributes (i.e. new attributes will appear quite frequently during the code's lifecycle), you might want to ask yourself, whether a RDBMS is the best way to materialize this ... essentially non-schema. Maybe a document store would be a better fit?
If you do want to stay in the RDBMS world, the canonical answer is to have either one or one-per-datatype property table plus a table of properties:
Users.id | .name | .birthdate | .Gender | .someotherfixedattribute
----------------------------------------------------------
1743 | Me. | 01/01/1970 | M | indeed
Propertytpes.id | .name
------------------------
234 | pet
235 | hobby
Poperties.uid | .pid | .content
-----------------------------
1743 | 234 | Husky dog
You have a comment and an answer that recommend (or at least suggest) and Entity-Attribute-Value (EAV) model.
There is nothing wrong with using EAV if your attributes need to be dynamic, and your system needs to allow adding new attributes post-deployment.
That said, if your columns and relationships are all known up front, and they don't need to be dynamic, you are much better off creating an explicit model. It will (generally) perform better and will be much easier to maintain.
Instead of a wide table with a field per attribute, or many attribute tables, you could make a skinny table with many rows, something like:
Attributes (id,user_id,attribute_type,attribute_value)
Ultimately the best solution depends greatly on how the data will be used. People can only have one DOB, but maybe you want to allow for multiple addresses (billing/mailing/etc.), so addresses might deserve a separate table.
I am creating a site that allows users to add a number of various items to their pages. These items can be very different from each other, such as text, images, numbers, etc. To handle this, I have one table that stores one entry for each item. The table has an id, the location of the item on the page, and the type of the item. I then have one table for each type of item which holds the more specific information about that item.
What I want to do is to set up an association so that when the page loads, it grabs the items from the main table in order - which is simple - and then also grabs the associated information from the proper table of specific information.
An example main_table could be:
id | location | type
1 | 1 | text
2 | 2 | image
3 | 3 | plot
4 | 4 | question
The table for text items may look like:
id | text |
1 | aaa |
2 | bbb |
The table for plots may look like:
id | type | datasets |
1 | bar | 3
2 | scatter | 2
So, can I set up an association where the main_data model pulls in the one associated file from the proper table? I could set up a separate model that selected the table for the specific information based on a passed in variable and set the source, but I am not sure how you would pass the variable with the type information to the model, nor am I sure if I am approaching this properly?
Thanks
PS
I had thought of the obvious - to combine the items into one table and simply have empty fields for everything not related to that item for each entry. So a text entry would still have columns for plot stuff, but they wouldn't be filled, etc. However, I wanted to be less wasteful of space - unless everyone thinks it would work better.
Sorry I don't have the reputation to comment for clarification, but this is what I made of your question. I think you're overthinking it...
The one thing that sticks out about your question, is that things are going to get very messy with the way you're approaching it.
In my opinion the best way to handle this is to give each item type it's own table then associations in the model definitions.
This is how your tables will look like, remember CakePHP tables need to be plural and user_id is deliberately titled as such.
Users
id | username
1 | example
Questions
id | user_id | text
1 | 1 | this is a question
Plots
id | user_id | text
1 | 1 | this is plot
This in your app/Model folder you will need files called User.php & Question.php & Plot.php (singular naming convention) that should look something like this
User.php
<?php
public $hasMany = array(
'Question',
'Plot'
);
?>
Question.php
<?php
public $belongsTo = 'User';
?>
Plot.php
<?php
public $belongsTo = 'User';
?>
Once you have set up the above, you will be able to easily access Plots and Questions in your views, I've provided below a snippet of a potential users controller and expected usage you can expect to use... learn to use debug() in CakePHP it's fantastic.
Controller/UsersController.php
<?php
...
public function index() {
$this->set('users', $this->paginate());
}
...
?>
View/Users/index.ctp
<div>
<?php
foreach ($users as $user):
debug($user);
echo $user['Question']['text'];
echo $user['Plot']['text'];
endforeach;
unset($user);
?>
</div>
After reading your question again, you mention "order" and "location". You can handle this by adding a column for "date_created" and "page_position" to each different table. I still feel like you overcomplicated your solution, and I hope I didn't miss something.
I want to understand how to use ReferenceProperty for common usage scenarios.
In a typical application, we always display Referenced Entity's columns.
For example, consider a Purchase Order application.
class POCategory(db.Model):
name = db.StringProperty()
class POSubCategory(db.Model):
category = db.ReferenceProperty(POCategory, collection_name='sub_categories')
name = db.StringProperty()
class PurchaseOrder(db.Model):
total_amount = db.FloatProperty()
class PurchaseOrderLineItem(db.Model):
category = db.ReferenceProperty(POCategory, collection_name='po_line_items')
sub_category = db.ReferenceProperty(POSubCategory, collection_name = 'po_line_items')
amount = db.FloatProperty()
This is what we normally display in typical applications.
+---------------+---------------+--------+
| Category | Sub Category | Amount |
+---------------+---------------+--------+
| Blue Category | Water | $12.00 |
| Red Category | Fire | $20.00 |
+---------------+---------------+--------+
| Purchase Order Total | $22.00 |
+---------------+---------------+--------+
Should I be using ReferenceProperty Pre-fetching for this to avoid N+1 select problem?
or
duplicate the category and sub-category names in my Purchase Order Line Item like below?
class PurchaseOrderLineItem(db.Model):
category = db.ReferenceProperty(POCategory, collection_name='po_line_items')
category_name = db.StringProperty()
sub_category = db.ReferenceProperty(POSubCategory, collection_name = 'po_line_items')
sub_category_name = db.StringProperty()
amount = db.FloatProperty()
Obviously, the names for categories and sub-categories are editable.
So when someone updates the name property, I will have to query and loop over all referenced PurchaseOrderLineItem entities and update my duplicate name properties.
#----------------------------------------
# BAD DESIGN
#----------------------------------------
po_category.name = 'New Category Name'
# build list of line items to be updated
update_list = []
for child_line_item in po_category.po_line_items:
child_line_item.category_name = po_entity.name
update_list.append(child_line_item)
db.put(po_category, update_list)
I know it is NOT a good scalable solution because over time we will have a lot of Line Items to be updated. RDBMS way of thinking is hard to get rid of.
So can anyone please teach me how to think for these kinds of typical scenarios?
Thanks!
As you said, since you can often edit category name, you should not embed it into Line Item.
Instead use NDB (which automatically caches gets) and multi-get (one DB call to get multiple entities) to get categories and sub-categories.
I have a collection of data like so
Programme title | Episode | Subtitle | Performers | Description
Initially I normalised this into two table like so
PROGRAMME
progid | progtitle | description
EPISODE
epid | progid | episode | subtitle | description
I'm thinking I'd like to represent the performers in another table though, but not sure how to represent it. From what I can tell the following relationships exist
One to Many: A programme can have many performers
One to Many: A performer could feature in many programmes
I'm not sure how I would represent this?
EDIT Ah I see so I'd actually have tables like this for example?
PERFORMER
performerid | performer
PROGRAMME
progid | progtitle | description
EPISODE
epid | progid | episode | subtitle | description
PROG_PERFORMER
progid | performerid
Also, performers can change between episodes
It's many-to-many. One performer can be in multiple programs, and one program can have multiple performers.
There's plenty of information on the net (and in textbooks) about setting up many-to-may relationships. One such resource is here:
http://www.tekstenuitleg.net/en/articles/software/database-design-tutorial/many-to-many.html
Really, though it should be
A Program has a one-many relationship with episodes
An episode has a many-many relationship with performers.
This is enough to create a query that will list all performer/show/episode relationships.
beside performer table you have to create a relation table
performer table
performerid | name | ...
relation table
performerid | progid
please help me on this one:)
Most of the time I am creating static pages like Contact Us, About Us, FAQs etc
If I want to store some dynamic items in the page, how will my table look like?
Let's say for the FAQ page, I am to store the question and the answer on the database. For the contact page, I will store emails and and some other contact information. Does that mean I have to create a separate table for each?
Often times I've seen people create a table for Meta information. It resembles a key => value relationship, where the first field of a row is the name and the second is the value. So if you were to manage your global contact information in the database, you may have the following rows:
Meta-Data Table
Meta ID | MetaTitle | Meta Value
---------------------------------------------------------
01 | email_address | some.guy#somedomain.com
02 | phone_number | 1.234.567.8901
03 | num_subscribers | 2312
04 | page_styles | background-color:#333333;color:#ffffff
As for your frequently asked questions, you could do that as a table, if you like:
Questions
Question ID | Question | Answer
-------------------------------------------
01 | How tall are you? | Not nearly tall enough.
Or you could simply create a generic 'pages' table:
Pages
Page ID | Page Title | Page Content
--------------------------------------------
01 | FAQs | How tall are you?
| | Not nearly tall enough.
--------------------------------------------
02 | Contact Us | Phone: 1.234.567.8901
| | Email: some.guy#somedomain.com
Based on the information provided, yes - it's quite likely you'll need separate tables.
Tables are just groupings of similar information, and email doesn't relate to questions & answers. With more information about what you're looking to do, and any business rules around it, we can help you with structure if you'd like.
You could just have 1 table which has a page id column and a page content column. The page id being different for each page you want to store in the database. And the page content column can be a text field which contains the HTML you want to display on that page. Then on each page you would query the database passing the parameter for the page content you wanted to display.