避免重复多态hasAndBelongsToMany通过模型关系

时间:2023-01-09 04:19:28

I have a rather complex relation with a polymorphic through-model. In the app, there is a tag system, where users and another model can be tagged. To avoid duplicate string entries, I used a through model (TagLink) which contains the tag ID, the tagged model name and the tagged instance ID.

我与多态通模型有着相当复杂的关系。在应用程序中,有一个标记系统,可以标记用户和另一个模型。为了避免重复的字符串条目,我使用了一个直通模型(TagLink),它包含标记ID,标记的模型名称和标记的实例ID。

So I have

所以我有

User --+
       |
       +---> TagLink -----------> Tag
       |      - tagId              - id
Item --+      - taggableId         - text
              - taggableName
                (User or Item)

The linking relation is hasAndBelongsToMany. The problem is, when I post a new tag to /items/:id/tags or /users/:id/tags, it is saved, but I can create as many as I want with the same text without any error.

链接关系是hasAndBelongsToMany。问题是,当我将新标签发布到/ items /:id / tags或/ users /:id / tags时,它会被保存,但我可以使用相同的文本创建任意数量的标签而不会出现任何错误。

What I would like is, upon posting to /items/:id/tags or /users/:id/tags, it :

我想要的是,发布到/ items /:id / tags或/ users /:id / tags后,它:

  • creates a new tag entry if it does not already exists, then adds a new TagLink entry (this is the current behaviour, but even when the same tag already exists)
  • 创建一个新的标记条目(如果它尚不存在),然后添加一个新的TagLink条目(这是当前行为,但即使已经存在相同的标记)
  • solely creates a TagLink entry when a tag already exists
  • 仅在标记已存在时创建TagLink条目

I thought about two solutions :

我想到了两个解决方案:

  • Somehow override the create method of Tag to check for existence, then manually create a TagLink entry if it exists. If not, proceed as by default.
  • 以某种方式覆盖Tag的create方法以检查是否存在,然后手动创建TagLink条目(如果存在)。如果没有,请默认继续。
  • Expose the tag list (/tags) with ~all CRUD URIs, then force to use the tag ID on /{items,users}/:id/tags.
  • 使用〜所有CRUD URI公开标记列表(/ tags),然后强制使用/ {items,users} /:id / tags上的标记ID。

Ideally, I would prefer the first one as it is more transparent and makes a smoother API.

理想情况下,我更喜欢第一个,因为它更透明,并使API更顺畅。

So, any leads would be welcome!

所以,任何线索都会受到欢迎!

1 个解决方案

#1


1  

I ended up doing the first solution, which was pretty easy. The idea is to replace the User.create method in a boot script which finds a tag with the same text, and returns it if one is found.

我最终做了第一个解决方案,这非常简单。我们的想法是在引导脚本中替换User.create方法,该脚本找到具有相同文本的标记,并在找到一个标记时返回它。

module.exports = function(app) {
    var Tag = app.models.Tag;

    // Override Tag.create to avoid duplicates
    Tag.createRaw = Tag.create;
    Tag.create = function(data, token, cb) {
        // Find matching tag
        Tag.findOne({where: {text: data.text}}, (err, tag) => {
            if (err)      cb(err);
            // If the tag is found, return it
            else if (tag) cb(null, tag);
            // Else create it
            else          Tag.createRaw(data, token, cb);
        });
    }
}

#1


1  

I ended up doing the first solution, which was pretty easy. The idea is to replace the User.create method in a boot script which finds a tag with the same text, and returns it if one is found.

我最终做了第一个解决方案,这非常简单。我们的想法是在引导脚本中替换User.create方法,该脚本找到具有相同文本的标记,并在找到一个标记时返回它。

module.exports = function(app) {
    var Tag = app.models.Tag;

    // Override Tag.create to avoid duplicates
    Tag.createRaw = Tag.create;
    Tag.create = function(data, token, cb) {
        // Find matching tag
        Tag.findOne({where: {text: data.text}}, (err, tag) => {
            if (err)      cb(err);
            // If the tag is found, return it
            else if (tag) cb(null, tag);
            // Else create it
            else          Tag.createRaw(data, token, cb);
        });
    }
}