Nosql 如何在DynamoDB中查询n:n邻接列表映射而不使用scan

Nosql 如何在DynamoDB中查询n:n邻接列表映射而不使用scan,nosql,amazon-dynamodb,aws-appsync,Nosql,Amazon Dynamodb,Aws Appsync,我正试图在DynamodDB中建立一个编目系统的模型。它有包含集合的目录。每个集合可以由多个标记进行标记 在RDBMS中,我将创建一个与集合具有1:n关系的表目录。集合将具有带标记的n:n,因为集合可以具有多个标记,并且一个标记可以属于多个集合 我要运行的查询包括: 我得到所有目录 2按ID获取目录 3按目录ID获取集合 我在AWS上读到,我可以使用邻接列表地图设计,因为我有带标签的n:n。下面是我的表结构: PK SK name cat-1 c

我正试图在DynamodDB中建立一个编目系统的模型。它有包含集合的目录。每个集合可以由多个标记进行标记

在RDBMS中,我将创建一个与集合具有1:n关系的表目录。集合将具有带标记的n:n,因为集合可以具有多个标记,并且一个标记可以属于多个集合

我要运行的查询包括:

我得到所有目录

2按ID获取目录

3按目录ID获取集合

我在AWS上读到,我可以使用邻接列表地图设计,因为我有带标签的n:n。下面是我的表结构:

PK         SK         name    
cat-1      cat-1      Sales Catalog
cat-1      col-1      Sales First Collection
cat-1      col-2      Sales Second Collection
cat-2      cat-2      Finance Catalog 
tag-1      tag-1      Recently Added Tag
col-1      tag-1      (collection, tag relationship)
这里的问题是,我必须使用一个扫描,我认为这是低效的,以便获取所有目录,因为查询的主键必须是“=”而不是“以开头”

我唯一能想到的就是创建另一个属性,比如GSI_PK,当PK是cat-1,SK是cat-1时添加Catalog_1,当PK是cat-2,SK是cat-2时添加Catalog_2。我从来没有真正看到这样做,所以我不确定这是否是一种方式去,它需要一些维护,如果我想改变ID


你知道我该如何做到这一点吗?

让我们来看看。我将使用graphqlsdl来布局数据模型和查询的设计,但是您可以直接将相同的概念应用到DynamoDB

首先考虑数据模型,我们将有如下内容:

type Catalog {
  id: ID!
  name: String

  # Use a DynamoDB query on the **Collection** table 
  # where the **catalogId = $ctx.source.id**. Use a GSI or make catalogId the PK.
  collections: [Collection]
}
type Collection {
  id: ID!
  name: String

  # Use a DynamoDB query on the **CollectionTag** table where
  # the **collectionId = $ctx.source.id**. Use a GSI or make the collectionId the PK.
  tags: [CollectionTag]
}
# The "association map" idea as a GraphQL type. The underlying table has a collectionId and tagId.
# Create objects of this type to associate a collection and tag in the many to many relationship.
type CollectionTag {
  # Do a GetItem on the **Collection** table where **id = $ctx.source.collectionId**
  collection: Collection

  # Do a GetItem on the **Tag** table where **id = $ctx.source.tagId**
  tag: Tag
}
type Tag {
  id: ID!
  name: String

  # Use a DynamoDB query on teh **CollectionTag** table where
  # the **tagId = $ctx.source.id**. If collectionId is the PK then make a GSI where this tagId is the PK.
  collections: [CollectionTag]
}

# Root level queries
type Query {
  # GetItem to **Catalog** table where **id = $ctx.args.id**
  getCatalog(id: ID!): Catalog

  # Scan to **Catalog** table. As long as you don't care about ordering on a filed in particular then
  # this will likely be okay at the top level. If you only want all catalogs where "arePublished = 1",
  # for example then we would likely change this.
  allCatalogs: [Catalog]

  # Note: You don't really need a getCollectionsByCatalogId(catalogId: ID!) at the top level because you can
  # use `query { getCatalog(id: "***") { collections { ... } } }` which is effectively the same thing.
  # You could add another field here if having it at the top level was a requirement
  getCollectionsByCatalogId(catalogId: ID!): [Collection]
}
注意:在我上面使用[Collection]或[Catalog]等的任何地方,您都应该使用CollectionConnection、CatalogConnection等包装类型来启用分页


让我们走过去。我将使用graphqlsdl来布局数据模型和查询的设计,但是您可以直接将相同的概念应用到DynamoDB

首先考虑数据模型,我们将有如下内容:

type Catalog {
  id: ID!
  name: String

  # Use a DynamoDB query on the **Collection** table 
  # where the **catalogId = $ctx.source.id**. Use a GSI or make catalogId the PK.
  collections: [Collection]
}
type Collection {
  id: ID!
  name: String

  # Use a DynamoDB query on the **CollectionTag** table where
  # the **collectionId = $ctx.source.id**. Use a GSI or make the collectionId the PK.
  tags: [CollectionTag]
}
# The "association map" idea as a GraphQL type. The underlying table has a collectionId and tagId.
# Create objects of this type to associate a collection and tag in the many to many relationship.
type CollectionTag {
  # Do a GetItem on the **Collection** table where **id = $ctx.source.collectionId**
  collection: Collection

  # Do a GetItem on the **Tag** table where **id = $ctx.source.tagId**
  tag: Tag
}
type Tag {
  id: ID!
  name: String

  # Use a DynamoDB query on teh **CollectionTag** table where
  # the **tagId = $ctx.source.id**. If collectionId is the PK then make a GSI where this tagId is the PK.
  collections: [CollectionTag]
}

# Root level queries
type Query {
  # GetItem to **Catalog** table where **id = $ctx.args.id**
  getCatalog(id: ID!): Catalog

  # Scan to **Catalog** table. As long as you don't care about ordering on a filed in particular then
  # this will likely be okay at the top level. If you only want all catalogs where "arePublished = 1",
  # for example then we would likely change this.
  allCatalogs: [Catalog]

  # Note: You don't really need a getCollectionsByCatalogId(catalogId: ID!) at the top level because you can
  # use `query { getCatalog(id: "***") { collections { ... } } }` which is effectively the same thing.
  # You could add another field here if having it at the top level was a requirement
  getCollectionsByCatalogId(catalogId: ID!): [Collection]
}
注意:在我上面使用[Collection]或[Catalog]等的任何地方,您都应该使用CollectionConnection、CatalogConnection等包装类型来启用分页


在这种情况下,可以将PK设置为对象的类型,将SK设置为uuid。记录看起来像{PK:Catalog,SK:uuid,…other Catalog fields}。然后可以通过对PK=Catalog进行查询来获取所有目录

要存储关联,可以在两个字段sourcePK和relatedPK上使用GSI,在这两个字段中可以存储关联事物的记录。要关联一个对象,您需要创建一个记录,例如{PK:Association,SK:uuid,sourcePK:category-1,relatedPK:collection-1,…关联上的其他数据}。要查找与id为1的目录关联的对象,可以在GSI上执行查询,其中sourcePK=Catalog-1


使用此设置时,您需要小心热键,并应确保表或索引中同一分区键下的数据不会超过10GB。

在这种情况下,您可以将PK设置为对象的类型,将SK设置为uuid。记录看起来像{PK:Catalog,SK:uuid,…other Catalog fields}。然后可以通过对PK=Catalog进行查询来获取所有目录

要存储关联,可以在两个字段sourcePK和relatedPK上使用GSI,在这两个字段中可以存储关联事物的记录。要关联一个对象,您需要创建一个记录,例如{PK:Association,SK:uuid,sourcePK:category-1,relatedPK:collection-1,…关联上的其他数据}。要查找与id为1的目录关联的对象,可以在GSI上执行查询,其中sourcePK=Catalog-1


使用此设置时,您需要小心热键,并应确保表或索引中同一分区键下的数据不会超过10GB。

因此,我需要一个n:n关系表,其中所有项都存储在一个表中。在根查询中,您有所有目录,您提到了我现在正在进行的扫描,但我知道在dynamo db中扫描效率很低,最好使用querySo基本上,我如何通过在相邻列表中查询dynamodb中的哈希键来获取所有目录n:n映射表在新的回答中响应所以我想要一个n:n关系表所有项目都存储在一个表中。在根查询中,您有所有目录,您提到了我现在正在进行的扫描,但我知道在dynamo db中扫描效率很低,最好使用querySo,基本上我如何通过在相邻列表中查询dynamodb中的哈希键来获得所有目录n:n映射表在新答案中响应OK我也在想同样的问题,添加一个类型列并在该列上创建一个GSI。好的,我的想法是一样的,添加一个类型列并在该列上创建一个GSI。