json 如何在GraphQL或REST系统中以动态方式正确发送更新/删除到嵌套记录?

nwsw7zdq  于 2023-05-02  发布在  其他
关注(0)|答案(1)|浏览(87)

我在这里有些重复,但我试图找出我API API,以便一次性更新所有深度嵌套的记录。
这个例子是一个字典,其中的“术语”是这样的模式:

{
  type: 'term',
  id: uuid,
  base: {
    id: termId,
  },
  singular: true,
  slug: 'create',
  plural: true,
  time: 'past, present, future',
  continuous: true,
  completed,
  aspect: 'verb',
  sense: 1,
  images: [
    
  ],
  gloss: {
    text: 'gloss'
  },
  etymology: {
    text: ''
  },
  origin: [
    {
      id: flowId,
    }
  ],
  derivations: [

  ],
  translations: [
    {
      id: termId
    }
  ],
  pronunciations: [
    {
      name: 'ipa',
      text: '',
    }
  ],
  definitions: [
    {
      text: '',
      similarities: [
        {
          id: termId,
        }
      ],
      definitions: [

      ]
    },
    {
      text: '',
      source: {
        id: citeId,
      }
    }
  ]
}

在最简单的情况下,我们通过API在嵌套树中创建每个对象,每次创建一个(假设我们处于“创建”阶段)。

POST /api/term { slug: 'foo' } => id == 123
POST /api/term/123/definition { text: 'hello' }
POST /api/term/123/definition { text: 'another' }
...

但这在几个方面似乎效率低下。但如果我们的UI表单在编辑每个输入后保存,则可能没有问题。实施起来可能有点棘手。
但更简单的方法是一次发送完整的JSON负载:

POST /api/term
{
  slug: 'foo',
  definitions: [
    { text: 'hello' },
    { text: 'another' },
  ]
}

这在这个“创建”的情况下工作得很好(与更新/删除相反),我只是在后端将其分解为单独的命令,就像我们之前所做的那样,但基本上是在DB级别。
但问题是如何做这种更“批处理”的方法,与更新和删除?看起来你真的不能以一种直截了当的方式做到这一点,这是对形势的正确阅读吗?
假设你已经创建了这个术语:

{
  slug: 'foo',
  definitions: [
    { text: 'hello' },
    { text: 'another' },
  ]
}

现在你想添加一个定义,你必须:

POST /api/term/:id/definition { text: 'a third' }

或者:

POST /api/term
{
  definitions: [
    { id: 1 },
    { id: 2 },
    { text: 'a third' },
  ]
}

但接下来就开始变得棘手了,我们用{ id: 1 }等是什么意思?我在想“保留我们刚刚通过ID传入的记录,并创建没有ID的记录”。但是如果你更复杂,说定义有一系列相关术语的“相似性”呢?

POST /api/term
{
  definitions: [
    { id: 1, similarities: [ { id: 125 } ] },
    { id: 2 },
    { text: 'a third' },
  ]
}

现在我们编辑第一条记录,并创建最后一条记录。
现在假设我们要删除第二个。在UI表单中,我们删除第二个,添加与第一个的相似性,然后创建第三个。

POST /api/term
{
  definitions: [
    { id: 1, similarities: [ { id: 125 } ] },
    { id: 2, _delete: true },
    { text: 'a third' },
  ]
}

是这样吗(借用我所记得的老Rails)。

总结/问题

总而言之,您可能有一个深度嵌套的记录,您可以在其中创建它的某些部分(嵌套记录),更新它的某些部分,并一次性删除它的某些部分。
从REST API或GraphQL API的Angular 来看,处理这种情况的标准方法是什么(基本上是将JSON发送到服务器的任何方法)?推荐的方法是什么,能够“批量”发送这些创建/更新/删除一次嵌套的JSON对象,并使其有效地写入PostgreSQL表?我不需要知道PostgreSQL的细节,只是说知道我的头在哪里。
自从我坐下来研究JSON API以来已经有一段时间了,所以现在已经有一段时间没有循环了,并且在我的记忆中没有处理这种情况的最佳方法。

其他注意事项

如果“字典术语”是一个很大的记录,比如有15个定义和很长的词源等等,那么每次更改一个条目时发送整个术语将是低效的。这就回到了第一个解决方案,即为每种记录类型设置API路由,并逐个调用它们。所以我有点困惑。
现在想想这样的事情:

{
  type: 'term',
  action: 'revision',
  properties: {
    definitions: [
      {
        action: 'revision',
        filter: {
          id: 123,
        },
        properties: {
          text: {
            action: 'overwrite',
            value: 'bar',
          }
        }
      },
      {
        action: 'deletion',
        filter: {
          id: 125
        }
      },
      {
        action: 'addition',
        properties: {
          text: 'foo'
        }
      },
    ]
  }
}
dkqlctbz

dkqlctbz1#

我最终这样做了,但更好的答案是受欢迎的!

查询

{
  action: {
    type: {
      slug: 'insert',
    },
  },
  filter: {
    type: 'flow',
  },
  select: {
    language: {
      id: true,
      slug: true,
      title: {
        id: true,
        transcription: {
          select: {
            script: {
              id: true,
            },
            gram: {
              id: true,
              text: true,
            },
          },
        },
      },
    },
    transcription: {
      size: true,
      select: {
        script: {
          id: true,
        },
        gram: {
          id: true,
          text: true,
        },
      },
    },
    pronunciation: {
      size: true,
      select: {
        gram: {
          id: true,
          text: true,
        },
      },
    },
  },
  effect: {
    language: {
      effect: {
        id: {
          effect: language.id,
        },
      },
    },
    transcription: [
      {
        action: {
          type: {
            slug: 'insert',
          },
        },
        effect: {
          script: {
            effect: {
              id: { effect: script.id },
            },
          },
          gram: {
            effect: {
              text: { effect: 'foo' },
            },
          },
        },
      },
    ],
    pronunciation: [
      {
        action: {
          type: {
            slug: 'insert',
          },
        },
        effect: {
          gram: {
            effect: {
              text: { effect: 'bar' },
            },
          },
        },
      },
      {
        action: {
          type: {
            slug: 'insert',
          },
        },
        effect: {
          gram: {
            effect: {
              text: { effect: 'bae' },
            },
          },
        },
      },
    ],
  },
}

响应

{
  language: {
    id: 'stub',
    slug: 'ghotuo',
    title: {
      id: 'stub',
      transcription: {
        list: [
          {
            script: { id: 'stub' },
            gram: { id: 'stub', text: 'Ghotuo' },
            id: 'stub',
          },
        ],
      },
    },
  },
  id: 'stub',
  transcription: {
    list: [
      {
        script: { id: 'stub' },
        gram: { id: 'stub', text: 'foo' },
        id: 'stub',
      },
    ],
    size: 1,
  },
  pronunciation: {
    list: [
      { gram: { id: 'stub', text: 'bar' }, id: 'stub' },
      { gram: { id: 'stub', text: 'bae' }, id: 'stub' },
    ],
    size: 2,
  },
}

摘要

它在很多方面都有点像GraphQL,你可以通过这种方式获取列表和列表的计数,使用select投影你想要的字段,并在选择查询的每个级别上进行过滤。然后使用effect指定要写入的属性。对于插入查询,只允许嵌套插入。但是对于更新查询,您可以分散插入/更新/删除。

相关问题