1

It's possible that I'm not quite understanding how hash/primary keys work in DynamoDB, but I'm trying to create a model (using Serverless + Dynogels/NodeJS) for a messaging service.

The model looks like this:

const ConversationORM = dynogels.define('Conversation', {

  hashKey: 'id',

  timestamps: true,
  tableName: config.CONVERSATION_TABLE,

  schema: {

    id: Joi.string(),
    users: Joi.array(), // e.g. ['foo', 'bar', 'moo']
    messages: Joi.array()

  }
})

As you can see, users is an array, which lists the userIds of the conversation's participants.

I need to create a service which finds all conversations that a user is participating in. In MongoDB (which I'm far more familiar with), I'd do something like:

Conversation.find({users: {"$in": ['foo']} }).then(.... 

Is there something equivalent I can do in DynamoDB? This is an API call that will happen quite often so I'm hoping to make it as efficient as possible.

2 Answers 2

2

This answer takes into account a comment on Hunter Frazier's answer saying you don't want to use a Scan.

When using a Query you need specify a single partition key in the operation. In your schema this would mean partitioning on the userid attribute, which is a set. Partition keys in DynamoDB must be a top-level scalar attribute. As userid is not scalar (its a set), you cannot use this attribute as an index, and therefore you cannot do a Query for the conversations a user is part of.

If you need to do this Query, I would suggest revisiting your schema. Specifically I would suggest implementing the Adjacency list pattern which works well in databases containing many-to-many relationships.

You can see some additional notes on the article above I have written on this answer DynamoDB M-M Adjacency List Design Pattern

In your case you would have:

  • Primary Key: ConversationID
  • Sort Key: UserID
  • GSI Primary Key: UserID

You can then use the GSI Primary key in a Query to return all conversations the user is part of.

Sign up to request clarification or add additional context in comments.

Comments

1

I'm not familiar with Dynogels or Serverless but if it uses the regular API this might work:

var params = {
    ExpressionAttributeNames: {
        "U": "users"
    },
    ExpressionAttributeValues: {
        ":a": {
            S: "John Doe"
        }
    },
    FilterExpression: "Author = :a",
    ProjectionExpression: "#U",
    TableName: "Conversations"
};
dynamodb.scan(params, function (err, data) {
    if (err) console.log(err, err.stack);
    else console.log(data);
});

1 Comment

Is there a way to do this without a full scan though? From what I've read they're expensive operations, and this will be a very-regularly-called endpoint so a full scan isn't ideal.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.