Deleting multiple items based on global secondary index in DynamoDB - amazon-dynamodb

I have an existing table which has two fields - primary key and a global secondary index:
----------------------------
primary key | attributeA(GSI)
----------------------------
1 | id1
2 | id1
3 | id2
4 | id2
5 | id1
Since having the attributeA as a global secondary index, can I delete all items by specifying a value for the global secondary index? i.e I want to delete all records with the attributeA being id1 - Is this possible in Dynamo?
Dynamo provides documentation about deleting the index itself, but not specifically if we can use the GSI to delete multiple items

As of now, you cannot delete an item just by passing Non-key attributes or GSI keys.
The simplest way to do this is to Query GSI and get primaryKey(Hash key of the table) and Delete in next request.
You can refer this answer if you want to do batchDeletion.
Hope that helps

Related

DynamoDB filter items not contains

I have the following problem:
Partition key (pk) and Sort key (sk):
pk sk
1 ITEMS#1
1 ORDERS#1
2 ITEMS#1
3 ITEMS#2
How can I retrieve all pk's that does not contain orders? I have tried the filter:
sk not contains "ORDERS"
But that returns
pk sk
1 ITEMS#1
2 ITEMS#1
3 ITEMS#2
Where I only want to return pk 2 and 3.
To do this efficiently, you'll have to pre-materialize the orders-or-not fact into your data and structure things in such a way that the fact is appropriately indexed and ready to use.
For example, you can create an item under each PK with an SK of META for metadata about that PK, and on that item you can have an attribute of HasOrders that's present if it has any orders in that item collection. Then you can create a GSI using that as the GSI partition key and very efficiently find all items that have orders with a Query.
You'll have to update the META every time someone places their first order.

DynamoDB Single Table Schema Design with Adjacency Lists

I am trying to understand how to properly design a DynamoDB schema. I've read a few articles, watched some YouTube videos but, to be honest, I don't yet feel quite comfortable.
This is what I am trying to design properly:
two entities, "location" (id & name) and "vehicle" (id & name)
a location can have 0-n vehicles
a vehicle can be in 0-1 locations
Access patterns:
get a list of all available locations (id & name)
get a list of all available vehicles and their current location (id, name, location-id, location-name)
get a list of all vehicles in a given location (id, name)
I've read about adjacency lists and because there will be n-m relations I've decided to give it a try.
This is what I've came up with:
# | PK (GSI1-SK) | SK (GSI1-PK) | DATA
==|======================|====================|==============
1 | LOCATION#locationId1 | A | locationName1
2 | LOCATION#locationId2 | A | locationName2
3 | LOCATION#locationId1 | VEHICLE#vehicleId1 |
4 | LOCATION#locationId1 | VEHICLE#vehicleId2 |
5 | LOCATION#locationId2 | VEHICLE#vehicleId3 |
6 | VEHICLE#vehicleId1 | A | vehicleName1
7 | VEHICLE#vehicleId2 | A | vehicleName2
8 | VEHICLE#vehicleId3 | A | vehicleName3
#1-2 & #6-8 are my entity records, those with additional data for the entity itself (e.g. its name).
#3-5 is an example of how I would design a relationship. I've added an inverted GSI in order to be able to search in both ways.
Back to my access patterns:
get a list of all available locations (id & name)
query GSI1 for SK=A and PK begins with LOCATION#
get a list of all available vehicles and their current location (id, name, location-id, location-name)
query GSI1 for SK=A and PK begins with VEHICLE#
for each result item, query GSI1 for SK=VEHICLE#vehicleId and PK begins with LOCATION#
for each result item, query table for PK=LOCATION#locationId and SK=A
... this doesn't seem right
get a list of all vehicles in a given location (id, name)
query table for PK=LOCATION#locationId and SK begins with VEHICLE#
for each result item, query table for PK=VEHICLE#vehicleId and SK=A
... this doesn't seem right
Adjacency lists look like a nice and clean way to design complex relationships but either I am doing something wrong (probably) or they come with alot of querys that are necessary to look things up.
Any advice is appreciated.
I modelled this in DynamoDB Workbench:
Main Index (PK -> SK)
GSI1 (PK1 -> SK)
In order to:
"get a list of all available locations (id & name)"
select * from GS1 where PK1="ALL#LOCATION"
get a list of all available vehicles and their current location (id, name, location-id, location-name)
select * from MAIN-INDEX where PK="ALL#VEHICLE"
get a list of all vehicles in a given location (id, name)
select * from GSI1 where PK1="LOC#ID"
Several things to here:
It's important to distribute the traffic across all partition keys. I'm using "ALL#" partition keys in this design. Ideally you shard that somehow, there are several tricks like using dates or timestamp to the beginning of the day. You can randomly spread them across a fixed number of "ALL#" records and then randomly query 1 if your use case allows it. If you have millions of locations this is probably ok. That's how you take these decisions: think of the traffic and the behaviour of the data.
In order to use both indexes I put the "ALL#LOCATION" and the "ALL#VEHICLE" partition keys in different indexes.
Notice that vehicle 4 doesn't have a PK1. See what happens to GSI1. This is what's called a sparse index.
I denormalized the vehicle-location relationship. Assuming that the location ID and the location name are immutable it's ok to do this, the problem is when the attributes you denormalize are mutable, avoid that if possible.

Dynamo DB - get only unique values from a table column

I have a table with 2 columns, user id & book id.
userId | bookId |
-----------------------
12 | 3
23 | 4
34 | 2
56 | 1
45 | 4
345 | 1
Is there a way to get only the unique values of bookId? like GROUP BY in sql.
Meaning query and get - [1,2,3,4]
Thanks.
DynamoDB doesn't have "columns" like a SQL table. Instead, it has documents (called items in DynamoDB terminology) which are indexed by a key (either simple or composite). And these items have attributes, but for the purposes of retrieval it's useful to imagine the items as being arbitrary payloads.
As such, there are no aggregate query APIs for DynamoDB tables. So you can't ask Dynamo to compute aggregations over multiple items.
If you need to identify unique items in a table you'll have to scan and perform the aggregation in your application. It's useful to think about how you might need to query the data upfront and use secondary indexes, or precompute aggregations as you update the data in your table.

Determining a partition key in Dynamo DB for GSI

I am new to DynamoDB and I am finding it hard to think of how I should decide my partition key. I am using a condensed version of my use case:
I have an attribute which is a boolean value => B
For a given ID, I need to return all the data for it. The ID is either X or Y attribute. For the given ID, if B is true, I need to read attribute X, else Y.
While inserting into the table I know the the value of B and hence I can fill it in either X or Y depending on the value of it.
However while fetching, I just am given an ID, and I need to figure out whether it exists in column X or column Y ( I won't be getting the value of B in the input).
In a RDBMS I could run a query like select * from tab where (B == true && X == ID) || (B==false && Y == ID).
I think creating a GSI in DynamoDB will be the way to go about solving this in Dynamo. However I am not able to figure out the best way to approach this. Could I get suggestions?
Not sure if I got your use case correctly, but why not just swapping target columns based on value B while inserting a row.
Consider the following input:
+-----+------+--------+
| X | Y | B |
+-----+------+--------+
| ID1 | ID2 | true |
+-----+------+--------+
| ID3 | ID4 | true |
+-----+------+--------+
| ID5 | ID6 | false |
+-----+------+--------+
| ID7 | ID8 | false |
+-----+------+--------+
What if you store the values like this:
+-----------+-------------------------+
| id | opposite id |
|(hash key) | or whatever you call it |
+-----------+-------------------------+
| ID1 | ID2 |
+-----------+-------------------------+
| ID3 | ID4 |
+-----------+-------------------------+
| ID6 | ID5 |
+-----------+-------------------------+
| ID8 | ID7 |
+-----------+-------------------------+
This way, while fetching an item by an IDXXX value you would need to perform a query on the single column id.
UPD: Notice, if your use case allows having multiple records with a same id, you would need an another field to serve as a range key. This holds true no matter whether you swap columns like shown above or not.
As Per AWS DynamoDB Blog Post : Choosing the Right DynamoDB Partition Key
Choosing the Right DynamoDB Partition Key is an important step in the
design and building of scalable and reliable applications on top of
DynamoDB.
What is a partition key?
DynamoDB supports two types of primary keys:
Partition key: Also known as a hash key, the partition key is composed of a single attribute. Attributes in DynamoDB are similar in
many ways to fields or columns in other database systems.
Partition key and sort key: Referred to as a composite primary key or hash-range key, this type of key is composed of two attributes. The
first attribute is the partition key, and the second attribute is the
sort key. Here is an example:
Why do I need a partition key?
DynamoDB stores data as groups of attributes, known as items. Items
are similar to rows or records in other database systems. DynamoDB
stores and retrieves each item based on the primary key value which
must be unique. Items are distributed across 10 GB storage units,
called partitions (physical storage internal to DynamoDB). Each table
has one or more partitions, as shown in Figure 2. For more
information, see the Understand Partition Behavior in the DynamoDB
Developer Guide.
DynamoDB uses the partition key’s value as an input to an internal
hash function. The output from the hash function determines the
partition in which the item will be stored. Each item’s location is
determined by the hash value of its partition key.
All items with the same partition key are stored together, and for
composite partition keys, are ordered by the sort key value. DynamoDB
will split partitions by sort key if the collection size grows bigger
than 10 GB.
Recommendations for partition keys
Use high-cardinality attributes. These are attributes that have
distinct values for each item like e-mail id, employee_no,
customerid, sessionid, ordered, and so on.
Use composite attributes. Try to combine more than one attribute to
form a unique key, if that meets your access pattern. For example,
consider an orders table with customerid+productid+countrycode as the
partition key and order_date as the sort key.
Cache the popular items when there is a high volume of read traffic.
The cache acts as a low-pass filter, preventing reads of unusually
popular items from swamping partitions. For example, consider a table
that has deals information for products. Some deals are expected to be
more popular than others during major sale events like Black Friday or
Cyber Monday.
Add random numbers/digits from a predetermined range for write-heavy
use cases. If you expect a large volume of writes for a partition key,
use an additional prefix or suffix (a fixed number from predeternmined
range, say 1-10) and add it to the partition key. For example,
consider a table of invoice transactions. A single invoice can contain
thousands of transactions per client.
Read More # Choosing the Right DynamoDB Partition Key

one to many unique "set" oracle db

I am not sure how to create a one to many relationship, but restrict the many items as a "set" to each unique primary key.
DB: Oracle 11g
Example:
PK Table:
CUST(PK)
100
200
Valid FK Table Data:
CUST(FK) | ITEM
100 | 101
100 | 102
200 | 101
200 | 102
Invalid FK Table Data:
CUST(FK) | ITEM
100 | 101
100 | 101
200 | 104
200 | 104
Any suggestions how to setup such a relationship? I'd like to limit the uniqueness so it is not possible to add a value to the FK table that violates the above "set" uniqueness.
Can this be done purely on the Oracle DB end, or must I enforce this from the accessing Java code?
Just create a unique constraint with two columns: CUST and ITEM, similar to:
ALTER TABLE secondtable
ADD CONSTRAINT custItem UNIQUE (CUST, ITEM)
Create this constraint in addition to your Foreign key
this might help you..create your tables following way....
create table cust_id
(cus_id number primary key)
tablespace ts1;
create table Valid_FK_Tabl
(cus_id number,item number,constraints pk1 primary key(cus_id,item))
tablespace ts1 ;
alter table Valid_FK_Tabl
add constraints fk1 foreign key(cus_id)
references schema2.cust_id(cus_id);

Resources