问答系统的正确数据库架构

时间:2018-10-12 18:24:02

标签: json database

我正在尝试构建一个系统,用户可以在其中添加问题,而其他用户可以对他的问题发表评论或投票。

主要功能是:

1. user can add a question.
2. user can comment on his or other users questions.
3. user can replay (comment) on his or other users comments.
4. user can vote on other users questions.

我构建的数据架构如下(示例):

Question: {
    id: "question_Q1",
    title: "How to learn python in one week?",
    body: "I am trying to learn a new language .............",
    images: {"python1.png","python2.png","python3.png","python5.png"},
    tags: {"python","programing"},
    user_id: "user_123456",
    voters: [ 
                 {id:"user_123457", username:"John F.M"},
                 {id:"user_123458", username:"Sarah K.P"} 
            ],
    create_timeDate: "02/01/2018 11:00 pm", 
    update_timeDate: "21/02/2018 10:12 am"
    comments: [ 
                 { id: "comment_c1", 
                   body:"you can learn it from ....", 
                   images: null, 
                   create_timeDate: "12/04/2018 11:00 pm", 
                   update_timeDate: "15/04/2018 10:12 am", 
                   replay: null}, 
                 { id: "comment_c2", 
                   body:"watch youtube for more information .....", 
                   images: {"youtube.gif"}, 
                   create_timeDate: "19/04/2018 09:43 pm", 
                   update_timeDate: "25/04/2018 11:10 pm", 
                   replay: [ 
                             { id: "replay_comment_c1", 
                               body:"ohh thanks", 
                               images: null, 
                               create_timeDate: "14/04/2018 01:00 am", 
                               update_timeDate: "20/04/2018 03:12 am", 
                               replay: null 
                              }, 
                            ] 
                 } 
              ]
}

我在做什么对吗?

那投票呢?我不知道如何在我的数据库架构中实现它。我想在堆栈溢出中执行相同的投票系统,但仅针对问题(不添加评论)。

1 个答案:

答案 0 :(得分:1)

我将创建以下表格:问题,图像,QuestionTag,QuestionVoters,QuestionTag和注释。

问题

QuestionID,
title,
body, 
user_id,

问题投票者

VoteID,
QuestionID (foreign Key to the Question table),
UserID

QuestionTagMapping

QuestionID (foreign key to the Question table)
TagID (foreign key to the Tags table)

QuestionTag

TagID
Tag

评论

Commentid,
QuestionID (foreign key to the Question table),
CommentReplyID: (if a comment replies to another comment put the id of this comment there),
body,
create_timeDate,
update_timeDate

图像

ID (ID of the Comment or the Question),
Image

更新

这里是一个示例,我将如何解决您的问题。我使用了SQL Server数据库。解释在注释中编写的代码中。

--store the user information here, you don't need to store any pw if you want 
--... we only need the iduser for our example

CREATE TABLE sUser 
(
    iduser varchar(100) PRIMARY KEY,
    username varchar(100) not null,
    --that could be other columns...
    /*
    --I have not stored any Password Hashes in DB, i am actually not sure if 1000 is the right length
    pwhash varchar(1000),
    email varchar(256),
    */
)

--store the Question and Comment data in this table
--I don't store Images or Tags in this table because I do no want to have multiple rows per post. 
--If you had multiple rows for one post, it would cause problems when you update the data
CREATE TABLE Post
(
    --I would not make the post id a varchar but in your example you defined a key for example like this 'question_Q1' 
    IDPost varchar(100) Primary Key,
    --is only filled if the post is a question
    title varchar(100) null,
    body text not null,
    iduser varchar(100) not null,
    --create the link to which question or comment a comment belongs
    ReplyID varchar(100) null,
    create_timeDate datetime2 not null,
    update_timeDate datetime2 not null,
    --creates an reference to the table itself, to a "mother" question or comment
    FOREIGN KEY (ReplyID) REFERENCES Post(IDPost),
    --creates a reference to the table users, so you can only insert a question or comment if the specified user exists
    FOREIGN KEY (iduser) REFERENCES sUser(iduser),
)

--stores votes
CREATE TABLE QuestionVoter 
(
    --with this column you can map the vote to the Question
    IDPost varchar(100) not null,
    --0 if the vote is negative, 1 if the vote is positive
    Vote bit not null,
    iduser varchar(100) not null,
    PRIMARY KEY(IDPost,iduser),
    --creates a reference to the table Post, so you can only insert a vote in this table if the PostID --> the Question exists in the Post table
    FOREIGN KEY (IDPost) REFERENCES Post(IDPost)
)

--here you can specify a set of Tags
CREATE TABLE QuestionTag 
(
    IDTAG int Primary Key,
    Tag varchar(100) not null
)

--create a mapping from a Question to the votes, the benefit for creating a mapping Table from the table Posts to the table QuestionTag,
--is that you can specify a set of gags and you don't have to store gags multipile times.  
CREATE TABLE QuestionTagMapping 
(
    --with this column IDPost you map the QuestionTag to the question
    IDPost varchar(100) not null,
    IDTAG int not null,
    PRIMARY KEY(IDPost, IDTAG),
    FOREIGN KEY (IDPost) REFERENCES Post(IDPost),
    FOREIGN KEY (IDTAG) REFERENCES QuestionTag(IDTAG)
)

--store your ImagePath in this table
CREATE TABLE Images 
(
    --this column is again for the mapping to the post
    IDPost varchar(100) NOT NULL,
    ImagePath varchar(256) not null,
    PRIMARY KEY(IDPOST, ImagePath),
    FOREIGN KEY (IDPost) REFERENCES Post(IDPost)
)

--example insert
--in your case i would not write plain sql, use a ORM Framework like JPA, Entity FrameWork Core to persist the data, but for this example its more then enough

--insert the Users
insert into sUser
values('user_123456','USER'),('user_123457','John F.M'),('user_123458','Sarah K.P')

--insert the Question
insert into Post
values('question_Q1', 'How to learn python in one week?', 'I am trying to learn a new language .............', 'user_123456',null,getdate(),getdate())

--insert the images for the Question
insert into Images
values('question_Q1','python1.png'),('question_Q1','python2.png')


--insert the votes for the question
insert into QuestionVoter
values('question_Q1', 1,'user_123457'),('question_Q1',1,'user_123458') --etc.

--specify QuestionTags
insert into QuestionTag
values(1, 'python'),(2, 'programming')
--select * from QuestionTag

--assagin the tags to a question via the QuestionTagMapping Table 
insert into QuestionTagMapping
values('question_Q1',1),('question_Q1',2)


--insert comments
insert into Post
values('comment_c1',/*title is null becouse comments dont have titles*/ null, 'you can learn it from ....','user_123457'
,/*insert the ReplyID to make a reference to question where the comment was postet*/ 'question_Q1',/*GETDATE() is just for example that the field have values*/GETDATE(), GETDATE())
,('comment_c2',null, 'watch youtube for more information .....','user_123457', 'question_Q1',GETDATE(), GETDATE())
,('replay_comment_c1',null, 'ohh thanks','user_123456', 'comment_c2',GETDATE(), GETDATE())

--Example queries

--Get the amount of votes
SELECT p.IDPost, count(*) as AmountVotes, sum(cast(v.Vote as int)) as PositivVotes, sum(IIF(v.Vote = 0,1,0)) as NegativVotes
FROM Post p
LEFT JOIN QuestionVoter v on p.IDPost = v.IDPost 
WHERE p.IDPost = 'question_Q1'
GROUP BY p.IDPost


--GET the comments for a question
SELECT * 
FROM Post q
--JOIN via the ReplayID the comments with questions or subcomments
LEFT JOIN Post c on q.IDPost = c.ReplyID
--get the sub comments with another join on ReplayID of the subcomment and the IDPost of the comments
LEFT JOIN Post sc on c.IDPost = sc.ReplyID
WHERE q.IDPost = 'question_Q1'