Внедрение комментариев и лайков в базе данных

157

Я разработчик программного обеспечения. Я люблю кодировать, но ненавижу базы данных ... В настоящее время я создаю веб-сайт, на котором пользователю будет разрешено пометить объект как понравившийся (как в FB), пометить его и комментировать .

Я застрял в дизайне таблиц базы данных для обработки этой функции. Решение тривиально, если мы можем сделать это только для одного типа вещей (например, фотографий). Но мне нужно включить это для 5 разных вещей (на данный момент, но я также предполагаю, что это число может расти по мере роста всей службы).

Я нашел здесь несколько похожих вопросов, но ни на один из них нет удовлетворительного ответа, поэтому я задаю этот вопрос еще раз.

Вопрос в том, как правильно, эффективно и эластично спроектировать базу данных, чтобы она могла хранить комментарии для разных таблиц , лайки для разных таблиц и теги для них. Какой-нибудь шаблон дизайна в качестве ответа будет лучшим;)

Подробное описание : у меня есть таблица User с некоторыми пользовательскими данными и еще 3 таблицы : Photoс фотографиями , Articlesсо статьями , Placesс местами . Я хочу разрешить любому зарегистрированному пользователю:

  • прокомментируйте любую из этих 3 таблиц

  • отметить любой из них как понравившийся

  • пометьте любой из них каким-нибудь тегом

  • Я также хочу подсчитать количество лайков для каждого элемента и количество раз, когда использовался этот конкретный тег.

1- й подход :

а) Для тегов , я создать таблицу Tag [TagId, tagName, tagCounter] , то я буду создавать много-ко-многим отношения таблиц для: Photo_has_tags, Place_has_tag, Article_has_tag.

б) То же самое относится к комментариям.

в) я создам таблицу LikedPhotos [idUser, idPhoto] , LikedArticles[idUser, idArticle], LikedPlace [idUser, idPlace]. Количество лайков будет подсчитываться по запросам (что, как я считаю, плохо). А также...

Мне этот дизайн в последней части очень не нравится, мне он плохо пахнет;)


2- й подход :

Я создам таблицу, ElementType [idType, TypeName == some table name]которая будет заполнена администратором (мной) с именами таблиц, которые можно лайкнуть , прокомментировать или пометить . Затем создам таблицы :

a) LikedElement [idLike, idUser, idElementType, idLikedElement]и то же самое для комментариев и тегов с соответствующими столбцами для каждого. Теперь, когда я хочу сделать фото понравившимся, я вставляю:

typeId = SELECT id FROM ElementType WHERE TypeName == 'Photo'
INSERT (user id, typeId, photoId)

и для мест:

typeId = SELECT id FROM ElementType WHERE TypeName == 'Place'
INSERT (user id, typeId, placeId)

и так далее ... Я думаю, что второй подход лучше, но я также чувствую, что в этом дизайне чего-то не хватает ...

Наконец, мне также интересно, где лучше всего хранить счетчик того, сколько раз понравился элемент. Я могу думать только о двух способах:

  1. в Photo/Article/Placeтаблице element ( )
  2. с помощью select count ().

Я надеюсь, что теперь мое объяснение вопроса более обстоятельно.

Кокос
источник
Вы рассматривали XML?
CodyBugstein
2
Я редко нахожу такие вопросы, которые на 100% совпадают с моими мыслями, ваш вопрос потрясающе закончен! Спасибо @Kokos.
aderchox

Ответы:

200

Наиболее расширяемое решение - иметь только одну «базовую» таблицу (связанную с «лайками», тегами и комментариями) и «наследовать» от нее все остальные таблицы. Добавление нового типа сущности включает в себя просто добавление новой «унаследованной» таблицы - затем она автоматически подключается ко всему подобному / tag / comment механизму.

Термин отношения сущностей для этого - «категория» (см. Руководство по методам ERwin , раздел «Отношения подтипов»). Символ категории:

Категория

Предполагая, что пользователю может нравиться несколько сущностей, один и тот же тег может использоваться для нескольких сущностей, но комментарий зависит от сущности, ваша модель может выглядеть следующим образом:

Диаграмма ER


Кстати, есть примерно 3 способа реализовать «категорию ER»:

  • Все виды в одной таблице.
  • Все типы бетона в отдельных таблицах.
  • Все конкретные и абстрактные типы в отдельных таблицах.

Если у вас нет очень строгих требований к производительности, третий подход, вероятно, является лучшим (это означает, что физические таблицы соответствуют 1: 1 объектам на диаграмме выше).

Бранко Димитриевич
источник
2
отличный ответ, спасибо. Надеюсь, мне удастся реализовать это ... и мне интересно, как Django ORM справится с этим (или как я сделаю это сам ... но это другая проблема;)) Но вы можете объяснить мне, потому что я думаю, что я не понимаю это должным образом - то, что вы нарисовали для меня (спасибо!), является третьим подходом, который вы упомянули?
Kokos
2
@Kokos По сути, подход (3) означает, что ENTITY - это таблица, PHOTO - это таблица, ARTICLE - это таблица, а PLACE - это таблица. Подход (2) означает, что нет нет таблицы для ENTITY и подхода (1) будет означать , есть только одна таблицы. Существование всех этих подходов (все со своими сильными и слабыми сторонами) является прискорбным следствием того факта, что типичная СУБД изначально не поддерживает наследование таблиц.
Бранко Димитриевич
1
+1 спасибо за отличное объяснение и ссылки на «категории». Я собирался задать вопрос, близкий к этому, но вы ответили на него здесь.
Энди Холадей 08
2
@BrankoDimitrijevic Почему таблицы сущностей Photo, Article, Place не могут иметь свой собственный PK, например PhotoID, ArticleID и т. Д., Но также иметь другой столбец для Entity_ID в качестве FK? В этом нет необходимости?
Том первый
3
@Orion Максимальное значение BIGINT- 9223372036854775807. Предполагая, что вы вставляете одну строку каждую секунду, вы исчерпаете доступные значения через ~ 300 миллиардов лет. Конечно, к тому времени вы сможете портировать на 128-битные целые числа!
Бранко Димитриевич
23

Если вы «ненавидите» базы данных, почему вы пытаетесь их реализовать? Вместо этого попросите помощи у того, кто любит это и дышит этим.

В противном случае научитесь любить свою базу данных. Хорошо спроектированная база данных упрощает программирование, проектирование сайта и упрощает его дальнейшую работу. Даже у опытного d / b-дизайнера не будет полного и идеального предвидения: некоторые изменения схемы потребуются в будущем по мере появления шаблонов использования или изменения требований.

Если это проект одного человека, запрограммируйте интерфейс базы данных на простые операции с использованием хранимых процедур: add_user, update_user, add_comment, add_like, upload_photo, list_comments и т. Д. Не встраивайте схему даже в одну строку кода. Таким образом, схему базы данных можно изменить, не затрагивая какой-либо код: о схеме должны знать только хранимые процедуры.

Возможно, вам придется несколько раз реорганизовать схему. Это нормально. Не беспокойтесь о том, чтобы сделать это идеально с первого раза. Просто сделайте его достаточно функциональным, чтобы создать прототип первоначального дизайна. Если у вас есть возможность потратить время, используйте его, а затем удалите схему и повторите попытку. Это всегда лучше второй раз.

Wallyk
источник
2
Потому что мне нужно реализовать это самому. По крайней мере, на данный момент ... и я подумал, что, может быть, это хороший повод, чтобы немного полюбить базы данных;) Спасибо за ваше предложение с хранимой процедурой. Кто-нибудь знает, автоматически ли они отображаются Django ORM?
Kokos
7
Мне нравится твоя последняя фраза - во второй раз всегда лучше.
Льюис
3
Второй раз всегда лучше. Ага
Gammer
21

Это общая идея, пожалуйста, не обращайте особого внимания на стили имен полей, а больше на отношения и структуру

введите описание изображения здесь

Этот псевдокод получит все комментарии к фотографии с ID 5
SELECT * FROM actions
WHERE actions.id_Stuff = 5
AND actions.typeStuff = "photo"
AND actions.typeAction = "comment"

Этот псевдокод получит все лайки или пользователей, которым понравилась фотография с идентификатором 5
(вы можете использовать count (), чтобы просто получить количество лайков)

SELECT * FROM actions  
WHERE actions.id_Stuff = 5  
AND actions.typeStuff="photo"  
AND actions.typeAction = "like"  
user964260
источник
Я думаю, вам даже могут понравиться комментарии, например, нажав на ссылку «нравится» в комментарии. Этот запрос получит лайки, SELECT * FROM actions WHERE actions.id=133 AND actions.typeStuff = "comment" AND actions.typeAction = "like"
похожие
1
Я обязательно запомню это решение для следующих выпусков моей системы :)
Kokos
У меня есть 2 таблицы материала stuff1 и stuff2 ... Я следил за этой диаграммой, но при использовании этого есть ошибка sql ... stuff1, stuff2 - две независимые таблицы с их независимыми первичными ключами, а таблица действий имеет столбец id_stuff, который ссылается на эти две таблицы stuff1, stuff2. Теперь, например, у stuff1 5 строк, у stuff2 10 строк, когда я пытаюсь добавить строку в таблицу действий с id_stuff, если значение меньше 5, скажем, «3», он выполняет запрос, потому что существует строка с id_stuff «3» как в stuff1, так и stuff2, но если я попытаюсь добавить строку с id_stuff больше 5 ... (перейти к следующему комментарию)
vikas devde
1
Если нужно реализовать лайки таким образом, это затруднит уведомление пользователя о новых лайках. Для этого потребуется другой стол.
Greg L
4
Как id_stuffстолбец будет содержать уникальные значения в каждой из трех таблиц?
Том первый
0

насколько я понимаю. требуется несколько таблиц. Между ними существует связь "многие ко многим".

  • Таблица, в которой хранятся пользовательские данные, такие как имя, фамилия, дата рождения, с полем идентификации.
  • Таблица, в которой хранятся типы данных. это могут быть фотографии, репосты, ссылки. у каждого типа должна быть уникальная таблица. следовательно, существует связь между их отдельными таблицами и этой таблицей.
  • у каждого типа данных есть своя таблица. например, обновления статуса, фото, ссылки.
  • последняя таблица предназначена для отношения многих ко многим, в которой хранятся идентификатор, идентификатор пользователя, тип данных и идентификатор данных.
Erencan
источник
если вы разместите свою схему базы данных. я могу нарисовать отношение.
erencan
0

Посмотрите на шаблоны доступа, которые вам понадобятся. Кажется ли что-нибудь из них особенно сложным или неэффективным, когда я выбрал тот или иной дизайн?

Если нет, отдайте предпочтение тому, для которого требуется меньше таблиц

В этом случае:

  1. Добавить комментарий: вы либо выбираете конкретную таблицу «много / много», либо вставляете в общую таблицу с известным конкретным идентификатором того, что нравится, я думаю, что во втором случае клиентский код будет немного проще.
  2. Найдите комментарии к элементу: здесь кажется, что использовать общую таблицу немного проще - у нас просто есть один запрос, параметризованный по типу сущности
  3. Находите комментарии человека об одном: в любом случае простой запрос
  4. Найдите все комментарии человека обо всем: в любом случае это кажется немного корявым.

Я думаю, что ваш «дискриминированный» подход, вариант 2, в некоторых случаях дает более простые запросы и не кажется намного хуже в других, поэтому я бы пошел с ним.

джна
источник
0

Рассмотрите возможность использования таблицы для каждой сущности для комментариев и т. Д. Больше таблиц - лучшее сегментирование и масштабирование. Управлять множеством похожих таблиц для всех известных мне фреймворков - не проблема.

Однажды вам нужно будет оптимизировать чтение из такой структуры. Вы можете легко создать сводные таблицы поверх базовых и немного потерять при записи.

Одна большая таблица со словарем может однажды выйти из-под контроля.

Ороборос102
источник
Больше таблиц означает, что его будет труднее обслуживать. Отдельные таблицы могут быть сегментированы большинством d / bs.
wallyk 02
-1

Определенно выберите второй подход, когда у вас есть одна таблица и храните тип элемента для каждой строки, это даст вам гораздо больше гибкости. В принципе, когда что-то логически можно сделать с меньшим количеством таблиц, почти всегда лучше использовать меньшее количество таблиц. Одно из преимуществ, которое приходит мне на ум прямо сейчас в вашем конкретном случае, учитывая, что вы хотите удалить все понравившиеся элементы определенного пользователя, с вашим первым подходом вам нужно выполнить один запрос для каждого типа элемента, но со вторым подходом это можно сделать только с одним запросом или подумайте, когда вы хотите добавить новый тип элемента, с первым подходом он включает создание новой таблицы для каждого нового типа, но со вторым подходом вы ничего не должны делать ...

никто
источник