Skip to content

Instantly share code, notes, and snippets.

@zmts
Last active November 13, 2020 01:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zmts/cb22cd51ecf43479d2f6d5368a6f3061 to your computer and use it in GitHub Desktop.
Save zmts/cb22cd51ecf43479d2f6d5368a6f3061 to your computer and use it in GitHub Desktop.
About Tags (Имплементация тегов)

Задача найти наиболее правильное и удобное решение имплементации функцианала 'Теги'

Дано:

  • RESTful API\PostgreSQL
  • Сущность TAG (таблица tags)
  • Все теги всех юзеров хранятся в одной таблице(tags). Названия тегов уникальны(qnique).
  • Сущность POST(новость, таблица posts)
  • Все посты всех юзеров хранятся в одной таблице(posts)
  • Отношение ManyToMany через posts_tags связующую таблицу
  • На момент добавления тега сущность поста создана и имеет свой уникальный ID

Задачи:

  • Получение всех постов по тегу
  • Получение поста со всеми связанными тегами
  • Добавление тега у клиента происходит во вьюхе редактирования поста
  • Добавление существующего тега к посту
  • Добавление нового тега к посту

Вариант первый:

  • Теги вводятся в специально отведенный для них блок(аля medium, evernote, github)
  • Теги в одном посте уникальны и не могут повторяться

Story:

  • Юзер начинает вводить название тега
    • Система автокомплита производит поиск тега(глобально по всем тегам в БД)
      • Юзер выбирает предложенный тег системой (1)
        • Система проверяет присуцтвует ли тег в посте
          • FALSE >> аттачит тег к посту(делает запись в связующей таблице posts_tags)
          • TRUE >> выдает ошибку
    • Юзер вводит новый тег(юзер игнорирует автокомплит)
      • Система смотрит нет ли такого же тега в БД
        • FALSE >> создает тег и аттачит тег к посту(делает запись в связующей таблице posts_tags)
        • TRUE >> Система проверяет присуцтвует ли этот тег в посте
          • FALSE >> аттачит тег к посту(делает запись в связующей таблице posts_tags)
          • TRUE >> выдает ошибку

Вариант второй:

  • Теги вносятся в тело поста(аля twitter, facebook)
  • Юзер может добавлять скольнеобходимое количество тегов(в разумных пределах)
  • Теги в одном посте не уникальны и могут повторяться

Story:

  • Юзер начинает вводить название тега
    • Система автокомплита производит поиск тега(глобально по всем тегам в БД)
      • Юзер выбирает предложенный тег системой (1)
        • Система проверяет присуцтвует ли тег в посте
          • FALSE >> добавляет ссылку на тег в контент поста и аттачит его к посту(делает запись в связующей таблице posts_tags)
          • TRUE >> добавляет только ссылку на тег в контент поста(дабы избежать дублирования в связующей таблице)
    • Юзер вводит новый тег(юзер игнорирует автокомплит)
      • Система смотрит нет ли такого же тега в БД
        • FALSE >> создает тег и аттачит его к посту(делает запись в связующей таблице posts_tags)
        • TRUE >> Система проверяет присуцтвует ли этот тег в посте
          • FALSE >> добавляет ссылку на тег в контент поста и аттачит его к посту(делает запись в связующей таблице posts_tags)
          • TRUE >> добавляет только ссылку на тег в контент поста(дабы избежать дублирования в связующей таблице)

(1) - Если желаемынй тег присуцтвует в списке предложенный системой, система принудительно вибирает тег из списка и аттачит его к посту. Что предотвращает ошибку в БД при попытке создать дубликат тега.

P.S.

  • Правильно ли представленны story для решения задачи ?
  • Каково ваше видение реализации подобного функционала ?
  • Если посмотреть на API github или twitter то у них ID в тегах не используются. Почему так ? Или они хайдят ID или ... ???
  • Прошу в комментарии, буду рад получить советы от более опытных разработчиков !)
// в итоге реализации первого варианта (node.js) >>
router.post('/:post_id/attachTag/:tag_id', attachTagToPost());
router.post('/:post_id/attachTag/', createAndAttachTagToPost());
/**
* ------------------------------
* description: attach Tag to Post
* ------------------------------
* access: owner, SU, ADMINROLES
* url: posts/:post_id/attachTag/:tag_id
* method: POST
*/
function attachTagToPost() {
return function (req, res) {
Post.checkTagByIdInPost(req.params.post_id, req.params.tag_id)
.then(function () {
return Post.attachTagToPost(req.params.post_id, req.params.tag_id);
})
.then(function (post) {
res.json({success: true, data: post});
})
.catch(function (error) {
res.status(error.statusCode || 403).send({success: false, description: error});
});
};
}
/**
* ------------------------------
* description: create and attach Tag to Post
* ------------------------------
* access: owner, SU, ADMINROLES
* url: posts/:post_id/attachTag/
* method: POST
* request: {"name": "string"}
*/
function createAndAttachTagToPost() {
return function (req, res) {
Tag.create(req.body)
.then(function (tag) {
return Post.attachTagToPost(req.params.post_id, tag.id);
})
.then(function (post) {
res.json({success: true, data: post});
})
.catch(function (error) {
res.status(error.statusCode || 403).send({success: false, description: error});
});
};
}
@zbitname
Copy link

zbitname commented Mar 1, 2017

@0136, в приведённой вами цитате ключевое слово "Переменная отношения находится". Нормальные формы применимы только в реляционных моделях. Реляционная модель - это когда значение ячейки имеет ссылку на другую сущность. Если ссылки на другую сущность нет - значит это не реляционная модель и ни о каких "нормальных формах" по отношению к этой модели говорить нельзя и не правильно вовсе.
Если вы используете РСУБД - это ещё не означает, что у вас там обязаны быть реляционные модели, вы их можете так организовать, но это не обязательно. Везде должен быть здравый смысл :)

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

Не плодите сущности без необходимости :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment