amazon-dynamodbdynamoose

Use beginsWith to search in sort key using dynamoose .get


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
});

Solution

  • 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.