clarkie / dynogels

DynamoDB data mapper for node.js. Originally forked from https://github.com/ryanfitz/vogels
Other
490 stars 110 forks source link

Create tables function call every time. #71

Closed rahulkulmi closed 7 years ago

rahulkulmi commented 7 years ago

I have used dynogels.createTables() function inside the every model. And i have found that every db call createTables function is executed so the response is getting from dynamoDB is slow like 1 second every request.

So if I have required 5 table to get interacted in one request so it takes 5-6 second which is not good.

So please tell me if i am doing some wrong implementation or is there any other way to call createTables function only one time if table is not there inside the database.

M1chaelTran commented 7 years ago

are you able to share how you are doing it?

Following the example, you only need call the createTables once. After which, you shouldn't need to call it again for every other CRUD methods.

rahulkulmi commented 7 years ago

Yes sure

var dynogels = require('dynogels');
var Joi = require('joi');
dynogels.AWS.config.update({
  accessKeyId: 'accessKeyId',
  secretAccessKey: 'secretAccessKey',
  region: 'region'
});

var userModel = dynogels.define('user', {
  hashKey: 'id',
  timestamps: true,
  schema: {
    id: dynogels.types.uuid(),
    name: Joi.string(),
    email: Joi.string().email(),
    rating: Joi.number()
  },
  indexes: [{
    hashKey: 'id',
    rangeKey: 'name',
    name: 'UserNameIndex',
    type: 'global'
  },
  {
    hashKey: 'id',
    rangeKey: 'email',
    name: 'UserEmailIndex',
    type: 'global'
  }]
});

dynogels.createTables({
  'user': {readCapacity: 1, writeCapacity: 1}
}, function(err) {
  if (err) { return err; }
});

module.exports = userModel;
M1chaelTran commented 7 years ago

hey @rahulkulmi

the code looks fine, but how are you calling the createTables, dynogels.define and the CRUD?

A trimmed down version of what I have in my project is on app start, I would define all the models before calling the createTables(...). At which, I could then call the CRUD methods against the model. Take note: all these are done against the same dynogel instant

eg. (sorry my code is in ES6, but i'm sure you can convert it to match ES5)

import dynogelWrapper from './DynogelsWrapper'
import userModel from './UserModel`
import accountModel from './AccountModel'

dynogelsWrapper.createTables(...)

dynogelWrapper is basically

import dynogels from 'dynogels'

dynogels.AWS.config.update({
  accessKeyId: 'accessKeyId',
  secretAccessKey: 'secretAccessKey',
  region: 'region'
});

class DynamoPersistent {

  defineSchema(tableName, tableSchema){
    dynogels.define(tableName, tableSchema)
  }

  createTables(){
    dynogels.createTables(...)
  }

}

export default const dynogelWrapper = new DynamoPersistent()

As for the UserModel, it is pretty much what you have. Except that you would import the same dynogelWrapper and then calling the defineSchema method.

If you are interested in a proper Data Access Layer where it is designed for scalability, then I recommend that you check out other repositories for more examples. My example is by all mean as an example to get you going and not something you would build for production.

Best of luck and happy hacking.

rahulkulmi commented 7 years ago

@M1chaelTran Thanks for give me good solution.

I am working on aws lambda function and my project is based on server less framework. Here I don't find a way to perform some operation before app start because in lambda function there is no app start that is why I have to keep createTables inside the model.

So if you know how to do dynogel wrapper in lambda function so please let me know.

M1chaelTran commented 7 years ago

oh, you should have mentioned that from the start!

i too have a few lambda functions working with dynomodb triggers and schedule tasks.

a few questions you might like to ask yourself are:

  1. do you really need an ORM (like dynogel) in your lambda? (because you can just call direct to dynamodb SDK provided by AWS)
  2. do you really want to create a table each time the lambda function run? (most of my cases, the table already exist, and all i needed to do is CRUD operations on it)
  3. if you still need to create the table every time and still wanted to use ORM in your lambda, then you going to expect a performance hit.

Keeping in mind that when you create a table with global secondary indexes, it going to take even longer time, which we all know that is an issue when it comes to lambda.

rahulkulmi commented 7 years ago
  1. Yes I need dynogel ORM
  2. No (only when if table is not there) I am also using CRUD operation only
  3. No I don't wanted to create table every time using dynogel
clarkie commented 7 years ago

My recommendation is to not use the dynogels createTables mechanism as part of your application start process. Due to the slow deployment of these tables your application can start very slowly. We've moved our create tables script to our CI build process and now don't need to worry about the tables being there at application runtime. I'd heavily recommend not using the createTables method in a lambda function.

wuichen commented 6 years ago

@rahulkulmi do u still have to use createtable for simple crud if you already have tables on dynamodb? im working on lambda as well

rahulkulmi commented 6 years ago

@wuichen YES i am still using createTables for CRUD if already have tables on dynamodb.

cdhowie commented 6 years ago

@rahulkulmi I would instead suggest having a Lambda function that only calls createTables, and have your build/CI system invoke this function after deploying any commits that change the model schemas.