1

I'm starting to learn Dynamodb here, and currently trying to do a search on my table where PK is the partition key and SK is the range key. PK contains an email address, whereas SK contains value like AB_STATE, BC_STATE, MY_STATE. So I want to search in the SK where the value starts with MY_ but I'm not entirely sure how to do it using .get() function.

Here's my query Seller.get({ "PK": "imin@cats.com", "SK" : "MY" }) which obviously isn't doing what I wants.

I am aware that I maybe can use filter like below, but I read in many places that using filter is not recommended (?)

var filter = new dynamoose.Condition().where("PK").eq(email).filter("SK").beginsWith("MY_");
var premiseProfile = await Seller.query(filter).exec()

Below is the schema for my Seller table

const schema = new dynamoose.Schema({
    PK: {
        type: String,   
        hashKey: true,
    },
    SK: {
        type: String,   
        rangeKey: true,
    },
    "firstName": String,
    "lastName": String,
    "gender": {
        "type": Number,
        "default": 0
    },
}, {
    "saveUnknown": true,
    "timestamps": true
});
imin
  • 4,504
  • 13
  • 56
  • 103

1 Answers1

2

When doing a Model.get call you must pass in an entire key. You can not pass in a key that starts with. This is due to the fact that Model.get will only return 1 item, and the query indicates that you could have multiple items there.

It's hard to answer your question exactly due to the fact that you didn't post your schema. But it looks like doing a query in this case isn't bad due to the fact that you are querying the data as opposed to filtering it.


Little bit more information based on comments.

I realized the condition.filter documentation doesn't really cover this as well as it should. Basically depending on your schema, it will determine the best index, and optimize it the best way it knows how.

For example, if you have the following code:

const dynamoose = require("dynamoose");

(async () => {
    dynamoose.model.defaults.set({
        "create": false,
        "waitForActive": false
    });

    const schema = new dynamoose.Schema({
        "PK": {
            "type": String,
            "hashKey": true
        },
        "SK": {
            "type": String,
            "rangeKey": true
        }
    });

    const Model = dynamoose.model("User", schema);

    dynamoose.logger.providers.add(console);

    const filter = new dynamoose.Condition().where("PK").eq("test@test.com").filter("SK").beginsWith("MY_");
    const premiseProfile = await Model.query(filter).exec()
})();

It will produce the following output:

aws:dynamodb:query:request - {
    "ExpressionAttributeNames": {
        "#qha": "PK",
        "#qra": "SK"
    },
    "ExpressionAttributeValues": {
        ":qhv": {
            "S": "test@test.com"
        },
        ":qrv": {
            "S": "MY_"
        }
    },
    "TableName": "User",
    "KeyConditionExpression": "#qha = :qhv AND begins_with (#qra, :qrv)"
}

As you can see it's using KeyConditionExpression as opposed to FilterExpression.

So you aren't filtering. If it makes more sense for you, you can use condition.where or condition.attribute.

It's important to note that in some cases it will use FilterExpression. But it will first look at your schema and try to see if it can use KeyConditionExpression, if it can, it'll use that, otherwise it'll use FilterExpression.

Charlie Fish
  • 18,491
  • 19
  • 86
  • 179
  • Ouch, can't believe I missed the part where `Model.get` return only an item in the doc. So it seems I can only use `query`. Regarding your last statement, why do you say so? I mean since I'm using `filter` in my `query`, doesn't that meant I'm doing filtering? – imin Mar 23 '21 at 08:07
  • 1
    @imin Just updated my answer to address that question. – Charlie Fish Mar 23 '21 at 14:23
  • 1
    Wow thanks a lot charlie, your answer is really informative, especially for someone who's just starting to use DynamoDB and Dynamoose like me. Thanks again!! – imin Mar 23 '21 at 17:19
  • Oh yeah one more thing, since as you mentioned, the docs don't cover condition.filter really well, may I know how you actually know that the query will produce the output `aws:dynamodb:query:request...` you wrote above? I looked into the condition.filter documentation page you gave above but couldn't find it mention what's really happening behind the scene – imin Mar 23 '21 at 17:40
  • 2
    @imin The `dynamoose.logger.providers.add(console);` line produces that output. Most of the code for handling that is [here](https://github.com/dynamoose/dynamoose/blob/dd40461cd49901dfde36bb4e299ea9ffd0369056/lib/DocumentRetriever.ts#L234-L252). Basically since you aren't using an index, it uses `KeyConditionExpression` for the hashKey, and optionally the rangeKey (if you are querying that also). – Charlie Fish Mar 23 '21 at 18:58