Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamodb scan() using FilterExpression

Tags:

First post here on Stack and fairly new to programming with Python and using DynamoDB, but I'm simply trying to run a scan on my table that returns results based on two pre-defined attributes.

---Here is my Python code snippet---

shift = "3rd" date = "2017-06-21"  if shift != "":     response = table.scan(         FilterExpression=Attr("Date").eq(date) and Attr("Shift").eq(shift)     ) 

My DynamoDB has 4 fields.

  1. ID
  2. Date
  3. Shift
  4. Safety

DynamoDB Pic

Now for the issue, upon running I'm getting two table entries returned when I should only be getting the first entry... the one with "No safety issues" based on my scan criteria.

---Here is my DynamoDB return results---

[   {     "Shift": "3rd",       "Safety": "No safety issues",       "Date": "2017-06-21",     "ID": "2"   },    {     "Shift": "3rd",      "Safety": "Cut Finger",      "Date": "2017-06-22",      "ID": "4"   } ] 

Items Returned: 2

I believe that by applying the FilterExpression with the logical 'and' specified that the scan operation is looking for entries that meet BOTH criteria since I used 'and'.

Could this be because the 'shift' attribute "3rd" is found in both entries? How do I ensure it returns entries based on BOTH criteria being meet and not just giving me results from one attribute type?

I have a feeling this is simple but I've looked at the available documentation at: http://boto3.readthedocs.io/en/latest/reference/services/dynamodb.html#DynamoDB.Table.scan and am still having trouble. Any help would be greatly appreciated!

P.S. I tried to keep the post simple and easy to understand (not including all my program code) however, if additional information is needed I can provide it!

like image 698
Torbyn Avatar asked Jun 22 '17 16:06

Torbyn


People also ask

How does Scan work DynamoDB?

A Scan operation in Amazon DynamoDB reads every item in a table or a secondary index. By default, a Scan operation returns all of the data attributes for every item in the table or index. You can use the ProjectionExpression parameter so that Scan only returns some of the attributes, rather than all of them.

What is Filterexpression in DynamoDB?

A filter expression determines which items within the Query results should be returned to you. All of the other results are discarded. A filter expression is applied after a Query finishes, but before the results are returned.

What is the difference between DynamoDB Scan and Query?

DynamoDB scans and GSIs. DynamoDB supports two different types of read operations, which are query and scan. A query is a lookup based on either the primary key or an index key. A scan is, as the name indicates, a read call that scans the entire table in order to find a particular result.


2 Answers

This is because you used Python's and keyword in your expression, instead of the & operator.

If a and b are both considered True, a and b returns the latter, b:

>>> 2 and 3 3 

If any of them is False, or if both of them are, the first False object is returned:

>>> 0 and 3 0 >>> 0 and '' 0 >>>  

The general rule is, and returns the first object that allows it to decide the truthiness of the whole expression.

Python objects are always considered True in boolean context. So, your expression:

Attr("Date").eq(date) and Attr("Shift").eq(shift) 

will evaluate as the last True object, that is:

Attr("Shift").eq(shift) 

which explains why you only filtered on the shift.

You need to use the & operator. It usually means "bitwise and" between integers in Python, it is redefined for Attr objects to mean what you want: "both conditions".

So you must use the "bitwise and":

FilterExpression=Attr("Date").eq(date) & Attr("Shift").eq(shift) 

According to the documentation,

You are also able to chain conditions together using the logical operators: & (and), | (or), and ~ (not).

like image 123
Thierry Lathuille Avatar answered Sep 28 '22 08:09

Thierry Lathuille


Dynamodb scan() using FilterExpression

For multiple filters, you can use this approach:

import boto3 from boto3.dynamodb.conditions import Key, And  filters = dict() filters['Date'] = "2017-06-21" filters['Shift'] = "3rd"  response = table.scan(FilterExpression=And(*[(Key(key).eq(value)) for key, value in filters.items()])) 
like image 26
Maxime Paillé Avatar answered Sep 28 '22 10:09

Maxime Paillé