diff --git a/www/src/pages/en/modeling/collections.mdx b/www/src/pages/en/modeling/collections.mdx index 4801322b..5cc6418e 100644 --- a/www/src/pages/en/modeling/collections.mdx +++ b/www/src/pages/en/modeling/collections.mdx @@ -16,7 +16,7 @@ layout: ../../../layouts/MainLayout.astro ## Overview -A Collection is a grouping of Entities with the same Partition Key and allows you to make efficient query across multiple entities. If your background is SQL, imagine Partition Keys as Foreign Keys, a Collection represents a View with multiple joined Entities. +A Collection is a grouping of Entities with the same Partition Key and allows you to make an efficient query across multiple entities. If your background is SQL, imagine Partition Keys as Foreign Keys, a Collection represents a View with multiple joined Entities. > ElectroDB Collections use a single DynamoDB query to retrieve results. One query is made to retrieve results for all Entities (the benefits of single table design), however keep in mind that DynamoDB returns all records in order of the Entity's sort key. In cases where your partition contains a large volume of items, it is possible some entities will not return items during pagination. This can be mitigated through the use of [Index Types](/en/modeling/indexes#index-types). @@ -52,7 +52,7 @@ export const Employee = new Entity({ type: "string", }, team: { - type: ["jupiter", "mercury", "saturn"], + type: ["jupiter", "mercury", "saturn"] as const, }, }, indexes: { @@ -182,7 +182,7 @@ await TaskApp.collections.assignments({ employeeId: "JExotic" }).go(); ## Collection Queries vs Entity Queries -To query across entities, collection queries make use of ElectroDB's Sort Key structure, which prefixes Sort Key fields with the collection name. Unlike an Entity Query, Collection queries for [isolated indexes](/en/modeling/indexes#isolated-indexes) only leverage [Composite Attributes](/en/modeling/indexes#composing-attributes) from an access pattern's Partition Key, while Collection queries for [clustered indexes](/en/modeling/indexes#clustered-indexes) allow you to query on both Partition and Sort Keys. +To query across entities, collection queries make use of ElectroDB's Sort Key structure, which prefixes Sort Key fields with the collection name. Unlike an Entity Query, Collection queries for [isolated indexes](/en/modeling/indexes#isolated-indexes) only leverage [Composite Attributes](/en/modeling/indexes#composite-attribute-arrays) from an access pattern's Partition Key, while Collection queries for [clustered indexes](/en/modeling/indexes#clustered-indexes) allow you to query on both Partition and Sort Keys. To better explain how Collection Queries are formed, here is a juxtaposition of an Entity Query's parameters vs a Collection Query's parameters: @@ -261,7 +261,7 @@ The notable difference between the two is how much of the Sort Key is specified Unlike Entity Queries which return an array, Collection Queries return an object. This object will have a key for every Entity name (or [Entity Alias](/en/modeling/services#creation)) associated with that Collection, and an array for all results queried that belong to that Entity. -For example, using the "TaskApp" models defined [above](#collections), we would expect the following response from a query to the "assignments" collection: +For example, using the "TaskApp" models defined [above](#entities), we would expect the following response from a query to the "assignments" collection: ### Example @@ -429,6 +429,7 @@ const tasks = new Entity({ }, indexes: { project: { + // highlight next line collection: "overview", pk: { field: "pk", @@ -478,6 +479,7 @@ const projectMembers = new Entity({ }, indexes: { members: { + // highlight next line collection: "overview", pk: { field: "pk", @@ -523,9 +525,9 @@ const TaskApp = new Service( [![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?#code/JYWwDg9gTgLgBAbwKIDsbBgTwDRwMoCmUAbsAMYEC+cAZlBCHAEQEA2BZM9AJgEZMAoMhBQBneDACGvdnAC8zMPQBWHGCEkpJAcwIgCaJgG4BQkeLh6wrCJgIFR8uCgIB3OKnRYAFAgFw4EAhuNgAuRH8AyzQMTHCWcBs7ByZsSIDiIlFgEXiARlT0uFEiUgp4qVEAa0kwMEKAyjSAyRguYF4AVxgHcL8oy0TbewBJbj6igKwwAnjxKGAUbUEBpqLobU1gAC9WnJQxiYGpzBm59qWVqLWBrX0j4+nZ5nnF5aKbqJ7JEAeBp-CAG1JlEmMpOmAMERUnAQQEmPooGROlBMDC4S9WiiUFcBgBdOCSRzCMQwD6RT6LEIAD16EQG4kkNBofyiYCqrIGNGAbHGiiqDWOAWE4Ag2R6QKYGy2u3QIjGTDxIM+DI59KFtB5rD5TGqgqFIsg4uegIS1mGBAVSqFlA+zSiViS9k5cGErHYnH28RJ7S6crE+qiVII1Pi2myACZAwF2S6AtzeWHI+zo1FDWKoZLHRarfbVnmotU45rE8xw8AI3qCwN08agXjq3AVU2KQImog4FIZAQmwBKUwkiyVKqOBQudyeWK+SJBEKsVkGLxxZjD0SBzJQbK5ZgFAslEjkZ5MYe1er2z6tX3dOn9L5EqqHdX-U5H16XO1FbPJR+359nF4XO8+ZFEoECqJwP4ggCAELO+wH-Bg7AutBuqAbiTYFrwwTLr+XwvucsFAdcFL2sGtKiKyoHgTALpuh6-rxBAG6kG4qaxk+xwJtq8Qpo2woMEamZwKaVFqFayqNkWHFclqOpVhitZCaaw7iTaH4DES2TaC4fK4fx7pqF6wkYkwPoLH6+xrrgJmacA2n6Gga4ggSRKuuYMCNmRSYVmxap6VEXE6uWEa8QpAkZhKwlmk6lrcIqjbNgEUn+fGsneZWAp8W5op1lFokQXFDYSeSjRtrgCCdtIsiUL2JhmKScD5TAACyei8FkTjjh4MQ+Les5hBxi6xDxKhqK1IDtZu65ZEZTC7kU+5lEeJ51IKF5tOZ14UYNQzfrpUH4TBbzoc2TWQUKKFvkRjQFnczz+ZdaHqRhkRkTeRT6BNWS0RABmetuUrMTyri+cWgU8ZlYU5UpTBnYVxVCslGLgy8kMatlgmRaaX6jPDanwWyo2cNt-l0YZ27AujpkiFe-pWbCVO2fZi5OUKLnEu5nkoDS6Wg9JAVpWWyZoxqilY9FOaFQlkl+cjgtMMF8no2LJpFTaBa2qV7YVV21W1bC9UWAAKveACCdSdW4+ClIevg4w4uCrrgTXjZNog1SYg7wPbYxOMeriSKwZAABbGKYJvVObYAAHRk-9YiRLHNObXTdu7bjNWJ9oEDeP2ATRzAwcGN43CtJI8gAHwcQA9NXbloCnlluX9-pwFABAwNijjt6InSsDAohFLXtD0Iwhc9jQv02K4bzRF4PIUUUXuIPbojO0TLVtVkjv3u7Til1IJiNP2AgR1UUdJy3lmJ0zKAOQPafmntmf59nueJ+PKAl2Xlc13XZkdG6E3OOrd26dygGINuDg+4DyHnXOgDBOxF1oFPCAM8lhzwwAvUIS93KIBdlvTcO9qh7wUAfSQR8+wmCAA) -> TypeScript Note: Use `as const` syntax when defining `collection` as a string array for improved type support +> TypeScript Note: Use `as const` syntax when defining `collection` as a string array for improved type support. -The last line of the code block above creates a Service called `TaskApp` using the Entity instances created above its declaration. By creating a Service, ElectroDB will identify and validate the sub-collections defined across all three models. The result in this case are four unique collections: "overview", "contributions", and "assignments". +The last code block above creates a Service called `TaskApp` using the Entity instances created above its declaration. By creating a Service, ElectroDB will identify and validate the sub-collections defined across all three models. The result in this case are three unique collections: "overview", "contributions", and "assignments". The simplest collection to understand is `overview`. This collection is defined on the table's Primary Index, composed of a `projectId` in the Partition Key, and is _currently_ implemented by two Entities: `tasks` and `projectMembers`. If another entity were to be added to our service, it could "join" this collection by implementing an identical Partition Key composite (`projectId`) and labeling itself as part of the `overview` collection. The following is an example of using the `overview` collection: @@ -545,7 +547,7 @@ const results = await TaskApp.collections ```typescript { data: { - tasks: [...], // tasks associated with projectId "SD-204 + tasks: [...], // tasks associated with projectId "SD-204" projectMembers: [...] // employees of project "SD-204" }, cursor: null, @@ -570,7 +572,7 @@ const results = await TaskApp.collections ### Complex Collections -Unlike `overview`, the collections `contributions`, and `assignments` are more complex. +Unlike `overview`, the collections `contributions` and `assignments` are more complex. In the case of `contributions`, _all three_ entities implement this collection on the `gsi2` index, and compose their Partition Key with the `employeeId` attribute. The `assignments` collection, however, is only implemented by the `tasks` and `projectMembers` Entities. Below is an example of using these collections: @@ -662,11 +664,11 @@ Looking above we can see that the `assignments` collection is actually a subset ElectroDB puts an emphasis on allowing users to define more domain specific naming. Instead of referring to indexes by their name on the table, ElectroDB allows users to define their indexes as Access Patterns. -> Please refer to the Entities defined in the section [Sub-Collections](/en/modeling/indexes#sub-collections) as the source of examples within this section. +> Please refer to the Entities defined in the section [Sub-Collections](/en/modeling/collections#sub-collections) as the source of examples within this section. ### Index Naming Conventions -The following is an access pattern on the "employees" entity defined [here](/en/modeling/#sub-collections): +The following is an access pattern on the "employees" entity defined [here](/en/modeling/collections#entities): ```typescript staff: { @@ -685,7 +687,7 @@ This Access Pattern is defined on the table's Primary Index (note the lack of an When deciding on an Access Pattern name, ask yourself, "What would the array of items returned represent if I only supplied the Partition Key". In this example case, the entity defines an "Employee" by its `organizationId` and `employeeId`. If you performed a query against this index, and only provided `organizationId` you would then expect to receive all Employees for that Organization. From there, the name `staff` was chosen because the focus becomes "What _are_ these Employees _to_ that Organization?". -This convention also becomes evident when you consider Access Pattern name becomes the name of the method you use query that index. +This convention also becomes evident when you consider that the Access Pattern name becomes the name of the method you use to query that index. ```typescript await employee.query.staff({ organizationId: "nike" }).go(); @@ -693,7 +695,7 @@ await employee.query.staff({ organizationId: "nike" }).go(); ### Collection Naming Conventions -The following are access patterns on entities defined [here](#sub-collection-entities): +The following are access patterns on entities defined [here](#entities): ```typescript // employees entity @@ -712,7 +714,7 @@ employee: { // tasks entity assigned: { - collection: ["contributions", "assignments"], + collection: ["contributions", "assignments"] as const, index: "gsi2", pk: { field: "gsi2pk",