Dynamoid / dynamoid

Ruby ORM for Amazon's DynamoDB.
MIT License
580 stars 194 forks source link

How to use condition expressions in a query? #608

Open nbulaj opened 1 year ago

nbulaj commented 1 year ago

Hey. I have a question about using Condition expressions with Dynamoid. See https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html

I have a users table with name: String and settings: Map attributes. Settings could contain a lot of different nested maps. I need to filter my query and find only users which has color setting in settings map, something like:

FilterExpression = 'attribute_exists(#0.#1)',
ExpressionAttributeNames = {
    "#0": "settings",
    "#1": "color"
},

Is it possible to add such condition to Dynamoid where query on using some plain AWS sdk call? Thanks :bow:

andrykonchin commented 1 year ago

I will check if it's possible to do it with QueryFilter/ScanFilter request parameters (that are deprecated now).

nbulaj commented 11 months ago

Sorry for bothering @andrykonchin , but maybe any update on this? Found filter_expression_convertor (https://github.com/Dynamoid/dynamoid/blob/6d53f100f0478bc04c7c45646771182df603fdc8/lib/dynamoid/adapter_plugin/aws_sdk_v3/filter_expression_convertor.rb#L54 ) don't know if it's possible to reuse it for my case.

andrykonchin commented 11 months ago

It seems QueryFilter/ScanFilter don't support conditions on collections like List and Map:

This parameter does not support attributes of type List or Map. https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html#DDB-Scan-request-ScanFilter https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LegacyConditionalParameters.QueryFilter.html

But recently where was switched from them to the Expressions style, that does support such conditions.

So right now 'settings.color.not_null' => true should not work but it seems easy to support it. Will try to add it soon and release in the next release.

nbulaj commented 8 months ago

Hi @andrykonchin . I see new version is here, I checked https://github.com/Dynamoid/dynamoid/pull/655/files but not sure how correctly to pass params to the .where method to filter by the Map fields which has some key :disappointed: Can you please help with that? Maybe we also need some READE section with how-to section on how to use new expressions

I still see:

field :metadata, :map 

# ...

Model.where("metadata.scores.not_null": true ).count

Traceback (most recent call last):
        1: from (irb):9
Dynamoid::Errors::Error (Unsupported operator screen_scores in metadata.scores.not_null)
nbulaj commented 8 months ago

OK I see Dynamoid::Criteria::Chain doesn't allow it via def field_condition which does the following:

name, operator = key.to_s.split('.')

So for where("settings.color.not_null": true) it returns => ["metadata", "screen_scores", "not_null"]

andrykonchin commented 8 months ago

The work is in progress (#696) - I will come back to it soon.