标签应该是自己的资源还是嵌套属性?

dip*_*ent 12 tags rest api-design

我正处于一个十字路口,决定标签应该是他们自己的资源还是笔记的嵌套属性.这个问题涉及RESTful设计和数据库存储.

上下文:我有一个笔记资源.用户可以有很多笔记.每个音符可以有很多标签.

功能目标: 我需要创建路由来执行以下操作:
1)获取所有用户标记.类似于:GET /users/:id/tags
2)删除与笔记相关联的标签.
3)将标签添加到特定注释.

数据/性能目标
1)获取用户标签应该很快.这是为了"自动提示"/"自动完成".
2)防止重复(尽可能多).我希望尽可能多地重用标签,以便能够按标签查询数据.例如,我想减轻用户在标签"超级英雄"已经存在时键入标签(如"超级英雄")的情况.

话虽如此,我看到它的方式,有两种方法可以在注释资源上存储标签:

1)标签作为嵌套属性.例如:

type: 'notes',
attributes: {
  id: '123456789',
  body: '...',
  tags: ['batman', 'superhero'] 
}
Run Code Online (Sandbox Code Playgroud)

2)标签作为自己的资源.例如:

type: 'notes',
data: {
  id: '123456789',
  body: '...',
  tags: [1,2,3] // <= Tag IDs instead of strings
}
Run Code Online (Sandbox Code Playgroud)

上述任何一种方法都可以工作,但我正在寻找一种能够实现可扩展性和数据一致性的解决方案(想象一百万个笔记和一千万个标签).在这一点上,我倾向于选项#1,因为它更容易处理代码,但可能不一定是正确的选择.

我非常有兴趣听到关于不同方法的一些想法,特别是因为我找不到关于这个主题的类似问题.

更新 感谢您的回答.对我来说最重要的事情之一是确定为什么使用一个优于另一个是有利的.我希望答案包含一些赞成/反对清单.

Div*_*ani 6

TL;博士

考虑到您的要求,您应该将IMO存储tags为资源,并且您的API应该notes将标记作为嵌入属性返回.


数据库设计

保持notestags作为单独的集合(或表).由于您有许多注释和许多标记,并且考虑到核心功能依赖于搜索/自动完成这些功能tags,这将在搜索notes特定内容时提高性能tags.一个非常基本的设计可能看起来像:

笔记

{
    'id': 101,    // noteid
    'title': 'Note title',
    'body': 'Some note',
    'tags': ['tag1', 'tag2', ...]
}
Run Code Online (Sandbox Code Playgroud)

标签

{
    'id': 'tag1',    // tagid
    'name': 'batman',
    'description': 'the dark knight',
    'related': ['tagx', 'tagy', ...],
    'notes': [101, 103, ...]
}
Run Code Online (Sandbox Code Playgroud)

您可以使用related属性替换来处理重复tagx,tagy通过类似的tags.


API设计

1.抓取notesuser:

GET /users/{userid}/notes
Run Code Online (Sandbox Code Playgroud)

在后端处理此路由时嵌入对象tags内部notes.该notes对象的API发送应该是这个样子:

{
    'id': 101,
    'title': 'Note title',
    'body': 'Some note',
    'tags': ['batman']    // replacing the tag1 by its name from tag collection
}
Run Code Online (Sandbox Code Playgroud)

2.抓取tagsuser:

GET /users/{userid}/tags
Run Code Online (Sandbox Code Playgroud)

如果不需要,您可以跳过发送notes包含id您的房产的房产notes.

3.删除tagsnotes:

DELETE /users/{userid}/{noteid}/{tag}
Run Code Online (Sandbox Code Playgroud)

4.添加tagsnotes:

PUT /users/{userid}/{noteid}/{tag}
Run Code Online (Sandbox Code Playgroud)

解决性能问题,获取tags用于user要快,因为你必须为同一个单独的集合.此外,处理重复项将更简单,因为您可以简单地将类似的tags(by idname)添加到related数组中.希望这有用.


为什么不将标记保留为嵌套属性

  • 该设计不像以前的情况那样可扩展.如果tags是嵌套属性并且tag必须编辑或者必须添加一些信息,那么它将需要更改所有,notes因为多个notes可以包含相同的内容tag.然而,保持tagsas资源,将相同的notes映射,ids并且tags集合/表中将需要单个更改.

  • 处理重复tags可能不像将它们保存为单独的资源那么简单.

  • 搜索时,tags您需要搜索所有tags嵌入的内部note.这增加了开销.


使用tags嵌套属性IMO 的唯一优势是它可以更容易地添加或删除tags特定的note.