बहुत से रास्ते हैं। यहाँ एक तरीका है जो मुझे पसंद है (और नियमित रूप से उपयोग करें)।
डेटाबेस
निम्नलिखित डेटाबेस संरचना पर विचार करें:
CREATE TABLE comments (
id int(11) unsigned NOT NULL auto_increment,
parent_id int(11) unsigned default NULL,
parent_path varchar(255) NOT NULL,
comment_text varchar(255) NOT NULL,
date_posted datetime NOT NULL,
PRIMARY KEY (id)
);
आपका डेटा इस तरह दिखेगा:
+-----+-------------------------------------+--------------------------+---------------+
| id | parent_id | parent_path | comment_text | date_posted |
+-----+-------------------------------------+--------------------------+---------------+
| 1 | null | / | I'm first | 1288464193 |
| 2 | 1 | /1/ | 1st Reply to I'm First | 1288464463 |
| 3 | null | / | Well I'm next | 1288464331 |
| 4 | null | / | Oh yeah, well I'm 3rd | 1288464361 |
| 5 | 3 | /3/ | reply to I'm next | 1288464566 |
| 6 | 2 | /1/2/ | this is a 2nd level reply| 1288464193 |
... and so on...
प्रयोग करने योग्य तरीके से सब कुछ चुनना काफी आसान है:
select id, parent_path, parent_id, comment_text, date_posted
from comments
order by parent_path, date_posted;
parent_path, date_posted
. द्वारा आदेश देना आम तौर पर परिणाम उस क्रम में प्रस्तुत करेंगे जिस क्रम में आपको अपना पृष्ठ बनाते समय उनकी आवश्यकता होगी; लेकिन आप यह सुनिश्चित करना चाहेंगे कि आपके पास टिप्पणी तालिका पर एक अनुक्रमणिका है जो इसका ठीक से समर्थन करेगी - अन्यथा क्वेरी काम करती है, लेकिन यह वास्तव में अक्षम है:
create index comments_hier_idx on comments (parent_path, date_posted);
किसी भी एकल टिप्पणी के लिए, उस टिप्पणी के बाल-टिप्पणियों के पूरे पेड़ को प्राप्त करना आसान है। बस जहाँ क्लॉज़ जोड़ें:
select id, parent_path, parent_id, comment_text, date_posted
from comments
where parent_path like '/1/%'
order by parent_path, date_posted;
जोड़ा गया जहां क्लॉज उसी इंडेक्स का उपयोग करेगा जिसे हमने पहले ही परिभाषित किया है, इसलिए हम जाने के लिए तैयार हैं।
ध्यान दें कि हमने parent_id
. का उपयोग नहीं किया है अभी तक। वास्तव में, यह कड़ाई से जरूरी नहीं है। लेकिन मैं इसे शामिल करता हूं क्योंकि यह हमें संदर्भात्मक अखंडता को लागू करने के लिए एक पारंपरिक विदेशी कुंजी को परिभाषित करने और यदि हम चाहें तो कैस्केडिंग डिलीट और अपडेट को लागू करने की अनुमति देता है। विदेशी कुंजी प्रतिबंध और कैस्केडिंग नियम केवल INNODB तालिकाओं में उपलब्ध हैं:
ALTER TABLE comments ENGINE=InnoDB;
ALTER TABLE comments
ADD FOREIGN KEY ( parent_id ) REFERENCES comments
ON DELETE CASCADE
ON UPDATE CASCADE;
पदानुक्रम का प्रबंधन
इस दृष्टिकोण का उपयोग करने के लिए, निश्चित रूप से, आपको यह सुनिश्चित करना होगा कि आपने parent_path
सेट किया है ठीक से जब आप प्रत्येक टिप्पणी सम्मिलित करते हैं। और यदि आप टिप्पणियों को इधर-उधर करते हैं (जो कि एक अजीब यूज़केस होगा), तो आपको यह सुनिश्चित करना होगा कि आप प्रत्येक टिप्पणी के प्रत्येक parent_path को मैन्युअल रूप से अपडेट करें जो कि स्थानांतरित टिप्पणी के अधीन है। ... लेकिन उन दोनों को बनाए रखना काफी आसान है।
यदि आप वास्तव में फैंसी प्राप्त करना चाहते हैं (और यदि आपका डीबी इसका समर्थन करता है), तो आप parent_path को पारदर्शी रूप से प्रबंधित करने के लिए ट्रिगर्स लिख सकते हैं - मैं इसे पाठक के लिए एक अभ्यास छोड़ दूंगा, लेकिन मूल विचार यह है कि ट्रिगर्स डालें और अपडेट करें आग लग जाएगी एक नया डालने से पहले प्रतिबद्ध है। वे पेड़ के ऊपर चलेंगे (parent_id
. का उपयोग करके) विदेशी कुंजी संबंध), और parent_path
. के मान का पुनर्निर्माण करें तदनुसार।
parent_path
. को तोड़ना भी संभव है एक अलग तालिका में बाहर जो पूरी तरह से टिप्पणी तालिका पर ट्रिगर द्वारा प्रबंधित की जाती है, कुछ विचारों या संग्रहीत प्रक्रियाओं के साथ आपको आवश्यक विभिन्न प्रश्नों को लागू करने के लिए। इस प्रकार अपने मध्य-स्तरीय कोड को पदानुक्रम जानकारी संग्रहीत करने के यांत्रिकी के बारे में जानने या देखभाल करने की आवश्यकता से पूरी तरह से अलग करना।
बेशक, किसी भी तरह से फैंसी सामान की आवश्यकता नहीं है - यह आमतौर पर केवल parent_path को तालिका में छोड़ने के लिए पर्याप्त है, और यह सुनिश्चित करने के लिए अपने मध्य-स्तर में कुछ कोड लिखें कि यह अन्य सभी क्षेत्रों के साथ ठीक से प्रबंधित हो जाता है आपको पहले से ही प्रबंधन करना होगा।
सीमाएं लगाना
MySQL (और कुछ अन्य डेटाबेस) आपको LIMIT
का उपयोग करके डेटा के "पृष्ठ" चुनने की अनुमति देता है खंड:
SELECT * FROM mytable LIMIT 25 OFFSET 0;
दुर्भाग्य से, इस तरह के पदानुक्रमित डेटा से निपटने पर, केवल LIMIT खंड वांछित परिणाम नहीं देगा।
-- the following will NOT work as intended
select id, parent_path, parent_id, comment_text, date_posted
from comments
order by parent_path, date_posted
LIMIT 25 OFFSET 0;
इसके बजाय, हमें उस स्तर पर एक अलग चयन की आवश्यकता है जहां हम सीमा लागू करना चाहते हैं, फिर हम अंतिम वांछित परिणाम देने के लिए अपनी "उप-पेड़" क्वेरी के साथ उस बैक में शामिल हो जाते हैं।
कुछ इस तरह:
select
a.*
from
comments a join
(select id, parent_path
from comments
where parent_id is null
order by parent_path, post_date DESC
limit 25 offset 0) roots
on a.parent_path like concat(roots.parent_path,roots.id,'/%') or a.id=roots.id)
order by a.parent_path , post_date DESC;
कथन पर ध्यान दें limit 25 offset 0
, आंतरिक चयन के बीच में दफनाया गया। यह कथन नवीनतम 25 "रूट-लेवल" टिप्पणियों को पुनः प्राप्त करेगा।
[संपादित करें:आप पा सकते हैं कि आपको चीजों को ऑर्डर करने और/या अपनी पसंद के अनुसार सीमित करने की क्षमता प्राप्त करने के लिए सामान के साथ थोड़ा सा खेलना होगा। इसमें पदानुक्रम के भीतर जानकारी जोड़ना शामिल हो सकता है जो parent_path
. में एन्कोड किया गया है . उदाहरण के लिए:के बजाय /{id}/{id2}/{id3}/
, आप post_date को parent_path के भाग के रूप में शामिल करने का निर्णय ले सकते हैं:/{id}:{post_date}/{id2}:{post_date2}/{id3}:{post_date3}/
. यह आपके इच्छित क्रम और पदानुक्रम को प्राप्त करना बहुत आसान बना देगा, इस खर्च पर कि आपको फ़ील्ड को ऊपर की ओर पॉप्युलेट करना होगा, और डेटा परिवर्तन के रूप में इसे प्रबंधित करना होगा]
आशा है कि यह मदद करता है। शुभकामनाएँ!