DynamoDb Update an Item from Node.js - amazon-dynamodb

I had the following code which originally worked for creating a user.
var params = {
TableName: 'myproject-user',
Item: {
id: req.body.userName,
email: req.body.email
}
};
if(req.body.currency) {
params.Item.currency = {
type: req.body.currency.type,
bank: req.body.currency.bank,
amount: req.body.currency.amount,
}
}
docClient.put(params, function(err, data) {
if (err) {
res.send({
success: false,
message: 'Error: ' + err
});
} else {
const { Items } = data;
res.send({
success: true,
message: 'Added user',
email: req.body.email
});
}
});
I'm now switching to put to update, as I want to be able to keep any existing values on the object while updating the email or name. In addition I have added the following line in the params object to specify the key which is id.
Key: { id : req.user.sub },
The doc.update code executes and I get back status 200 as if there was no problem, but when I look at the table the information hasn't been updated.
Do I need to use an expression or something to get update to work?
Code with changes:
var params = {
TableName: 'myproject-user',
Key: {"id":req.user.sub},
Item: {
id: req.body.userName,
email: req.body.email
}
};
docClient.update(params, function(err, data) {
if (err) {
res.send({
success: false,
message: 'Error: ' + err
});
} else {
const { Items } = data;
res.send({
success: true,
message: 'Added user',
email: req.body.email
});
}
});

I was able to get this working by using UpdateExpression, ExpressionAttributeValues, and ReturnValues attributes instead of Item, as described here:
var params = {
TableName: 'krncdev-user',
Key: {"id":req.user.sub},
UpdateExpression: "set email=:e",
ExpressionAttributeValues:{
":e": req.body.email
},
ReturnValues:"UPDATED_NEW"
};

Related

Confused on creating an update request for DynamoDB using API Gateway

I'm writing a lambda function to get the resources by posting the phone number. below is my code.
exports.handle = function (e, ctx, cb) {
var body = JSON.parse(e.body);
var params = {
TableName: 'userAddresses',
FilterExpression: '#phone = :phone',
ExpressionAttributeNames: {
"#phone": "phone"
},
ExpressionAttributeValues: {
":phone": body.phone
}
}
dynamodb.scan(params).promise().then(function (data) {
var uw = data.Items[0];
var res = {
"statusCode": 200,
"headers": {},
"body": JSON.stringify(uw)
};
ctx.succeed(res);
});
}
this is working fine. but I want to do the same with put and patch. Can some one please point me in a right direction.
for patch, it should be something like, the phone should be passed as a queryParameter and the body to be updated in just json body
Thanks
Is the phone number a hash key? If so, use dynamodb.get() or dynamodb.query() instead...
Here's a quick and dirty example, it may help you to get started with DynamoDB updates:
const AWS = require('aws-sdk);
const bluebird = require('bluebird');
AWS.config.setPromisesDependency(bluebird);
const dynamodb = new AWS.DynamoDB.DocumentClient();
let update = (id, attributes) => {
var params = {
TableName: 'MyTableName',
Key: {
myHashKeyAttr: id
},
AttributeUpdates: attributes
};
return dynamodb.update(params).promise();
};
exports.handler = (event, context, callback) => {
console.log(JSON.stringify(event, null, 2));
let body = JSON.parse(event.body);
let attributes = {
firstName: {
Action: 'PUT',
Value: body.firstName
},
lastName: {
Action: 'PUT',
Value: body.lastName
},
updatedAt: {
Action: 'PUT',
Value: new Date()
}
};
// only if the phone number is a hash key...
update(event.queryStringParameters.phone, attributes)
.then(
(result) => {
console.log(result);
callback({
statusCode: 200,
headers: {},
body: JSON.stringify({message: 'updated!'})
});
}
).catch(
(error) => {
console.error(error);
callback({
statusCode: 500,
headers: {},
body: JSON.stringify({message: 'ops!'})
});
}
);
}

SimpleSchema insert fails with unhelpful error unless {validate: false} is set

At this point I've actually pared down my code to mimic the example in the docs, and I'm getting the same error.
I've defined my Collection as such:
var Categories = new Mongo.Collection('categories');
const CategorySchema = new SimpleSchema({
title: {
type: String,
label: "Title",
max: 255,
optional: true
},
created: {
type: Date,
label: "Date Category Created",
autoValue: () => {
if(this.isInsert){
return new Date();
} else if (this.isUpsert) {
return {$setOnInsert: new Date()};
}
}
},
updated: {
type: Date,
label: "Date Category Modified",
autoValue: () => {
if(this.isUpdate){
return new Date();
}
},
optional: true
}
});
Categories.attachSchema(CategorySchema);
export { Categories };
The autovalue stuff is borrowed straight from the docs.
And have a method for calling insert:
Meteor.methods({
'categories.insert'(title){
check(title, String);
Categories.insert({title: title}, (err, res) => {
if(err){
console.error("Category insert failed: " + err);
}
});
},
...
As I've tried to get through this issue, I've added and removed rules to the schema definition, sometimes getting a call stack exceeded error. Mostly what I get is the following:
Exception while simulating the effect of invoking 'categories.insert' TypeError: func is not a function
at http://localhost:3000/packages/modules.js?hash=fefb674368e70344875cb9448e3ea784a880ffb0:13027:18
at Array.forEach (native)
at doValidation (http://localhost:3000/packages/modules.js?hash=fefb674368e70344875cb9448e3ea784a880ffb0:13026:17)
at ValidationContext.validate (http://localhost:3000/packages/modules.js?hash=fefb674368e70344875cb9448e3ea784a880ffb0:12580:57)
at ns.Collection.doValidate (http://localhost:3000/packages/aldeed_collection2-core.js?hash=0564817159bbe9f8209b6a192a1fa2b2bbab924a:466:33)
at ns.Collection.Mongo.Collection.(anonymous function) [as insert] (http://localhost:3000/packages/aldeed_collection2-core.js?hash=0564817159bbe9f8209b6a192a1fa2b2bbab924a:260:25)
at ns.Collection.<anonymous> (http://localhost:3000/packages/matb33_collection-hooks.js?hash=d44fd0eb02806747e1bb0bdc3938463e415c63ec:402:19)
at ns.Collection.collection.(anonymous function) [as insert] (http://localhost:3000/packages/matb33_collection-hooks.js?hash=d44fd0eb02806747e1bb0bdc3938463e415c63ec:155:21)
at DDPCommon.MethodInvocation.categories.insert (http://localhost:3000/app/app.js?hash=580bf82f2f196202280f32cf5ffacbc930cd6b10:20073:14)
at http://localhost:3000/packages/ddp-client.js?hash=c9ca22092a3137a7096e8ab722ba5ab8eedb9aec:4076:25 TypeError: func is not a function
at http://localhost:3000/packages/modules.js?hash=fefb674368e70344875cb9448e3ea784a880ffb0:13027:18
at Array.forEach (native)
at doValidation (http://localhost:3000/packages/modules.js?hash=fefb674368e70344875cb9448e3ea784a880ffb0:13026:17)
at ValidationContext.validate (http://localhost:3000/packages/modules.js?hash=fefb674368e70344875cb9448e3ea784a880ffb0:12580:57)
at ns.Collection.doValidate (http://localhost:3000/packages/aldeed_collection2-core.js?hash=0564817159bbe9f8209b6a192a1fa2b2bbab924a:466:33)
at ns.Collection.Mongo.Collection.(anonymous function) [as insert] (http://localhost:3000/packages/aldeed_collection2-core.js?hash=0564817159bbe9f8209b6a192a1fa2b2bbab924a:260:25)
at ns.Collection.<anonymous> (http://localhost:3000/packages/matb33_collection-hooks.js?hash=d44fd0eb02806747e1bb0bdc3938463e415c63ec:402:19)
at ns.Collection.collection.(anonymous function) [as insert] (http://localhost:3000/packages/matb33_collection-hooks.js?hash=d44fd0eb02806747e1bb0bdc3938463e415c63ec:155:21)
at DDPCommon.MethodInvocation.categories.insert (http://localhost:3000/app/app.js?hash=580bf82f2f196202280f32cf5ffacbc930cd6b10:20073:14)
at http://localhost:3000/packages/ddp-client.js?hash=c9ca22092a3137a7096e8ab722ba5ab8eedb9aec:4076:25
meteor.js?hash=27829e9…:930 Error invoking Method 'categories.insert': Internal server error [500]
EDIT
After swapping out the arrow functions:
methods.js
Meteor.methods({
// Settings: create new category
'categories.insert': function(title){
check(title, String);
Categories.insert({title: title}, function(err, res){
if(err){
console.error("Category insert failed: " + err);
}
});
},
...
settings.js
Template.settings.onCreated(function(){
Meteor.subscribe('categories');
});
Template.settings.helpers({
categories: function(){
return Categories.find();
}
});
Template.settings.events({
'click #newCategoryButton': function(e){
let title = $("#newCategoryInput").val();
if(title !== ""){
Meteor.call('categories.insert', title);
$("#newCategoryInput").val("").focus();
}
},
'click .removeCategory': function(e){
var id = $(e.currentTarget).data('id');
Meteor.call('categories.remove', id);
}
});
Categories.js
var Categories = new Mongo.Collection('categories', options);
const CategorySchema = new SimpleSchema({
title: {
type: String,
label: "Title",
max: 255,
optional: true
},
created: {
type: Date,
label: "Date Category Created",
autoValue: function(){
if(this.isInsert){
return new Date();
} else if (this.isUpsert) {
return {$setOnInsert: new Date()};
}
}
},
updated: {
type: Date,
label: "Date Category Modified",
autoValue: function(){
if(this.isUpdate){
return new Date();
}
},
optional: true
}
});
Categories.attachSchema(CategorySchema);
Still getting the same error as in original post
You're using arrow functions like Sean mentioned in the comment. Replace them with traditional function(){...} and you should be good to go.
You can read more about this issue here

Error when updating an object in auto-form with meteor

I have checked the docs but I cannot get my head around this. I have an object that I want to update using Auto-Form and Collections2 with meteor.
//Schema
Records = new Mongo.Collection('records');
var Schemas = {};
Schemas.Record = new SimpleSchema({
title: {
type: String,
label: "Title",
max: 200
},
caption: {
type: String,
label: "Caption",
max: 200
},
text: {
type: String,
label: "Detailed text",
optional: true,
max: 1000
},
loc: {
type: Object,
optional: true,
blackbox: true
},
createdAt: {
type: Date,
autoform: {
type: "hidden"
},
autoValue: function() {
if (this.isInsert) {
return new Date;
}
else if (this.isUpsert) {
return {
$setOnInsert: new Date
};
}
else {
this.unset();
}
}
},
updatedBy: {
type: String,
autoValue: function() {
return Meteor.userId();
}
}
});
Records.attachSchema(Schemas.Record);
I have a hook so that I assign the object before update
AutoForm.hooks({
insertCommentForm: {
before: {
insert: function(doc) {
doc.commentOn = Template.parentData()._id;
return doc;
}
}
},
updateRecordForm: {
before: {
update: function(doc) {
console.log("storing location data");
doc.loc = Session.get('geoData');
console.log(doc.loc);
return doc;
}
}
}
});
I get this error.
Uncaught Error: When the modifier option is true, all validation
object keys must be operators. Did you forget $set?
I don't know how to "$set" with autoform.
when you are trying to update a document in Mongo, when you want to update only certain fields, you will use the $set modifier.
Records.update({ _id: 1 }, { $set: { loc: { lat: 12, lng: 75 } } })
The above would update only the loc value.
Records.update({ _id: 1 }, { loc: { lat: 12, lng: 75 } })
The above would remove all other keys and the record will only have the _id and the loc.
Your hook will have to set the loc key in doc.$set.
Please update your hook with the following code and it should work:
updateRecordForm: {
before: {
update: function(doc) {
console.log("storing location data", doc);
doc.$set.loc = Session.get('geoData');
return doc;
}
}
}

FS.Collection Image ID don't validate check()

I'm trying to save image id after insert in FS.Collection.
Insert array
var item = {
name: $(value).find('#name').val(),
article: $(value).find('#article').val(),
description: $(value).find('#description').val(),
price: $(value).find('#price').val(),
sizes: $(value).find('#sizes').val()
};
file = $(value).find('#attachmentName')[0].files[0];
if (file !== undefined) {
Images.insert(file, function (err, fileObj) {
item = _.extend(item, {
image: fileObj._id.toString()
});
});
}
Meteor.call('collectionInsert', item, function(error, result) {
if (error)
return alert(error.reason);
Router.go('collection', {_id: result._id});
});
collectionInsert method
Meteor.methods({
collectionInsert: function(postAttributes) {
check(Meteor.userId(), String);
check(postAttributes, {
name: String,
article: String,
description: String,
price: String,
sizes: String,
image: String
});
var user = Meteor.user();
var post = _.extend(postAttributes, {
userId: user._id,
author: user.profile.name,
timestamp: new Date(),
views: 0
});
var collectionId = Collections.insert(post);
return {
_id: collectionId
};
}
});
Then i'm got Exception
Exception while invoking method 'collectionInsert' Error: Match error: Missing key 'image'
In console log i have item value
...
image: "4J55dyGb5DpqbCXGG"
...
I'm trying to change check property to image: Match.Optional([String]) and image: Match.Any - no effect
I think the issue here is that your insert method is non-blocking, which means that you probably haven't received the fileObj nor extended item before passing it to the method call. Maybe you should try to make the method call in the insert callback, like this:
if (file !== undefined) {
Images.insert(file, function (err, fileObj) {
item.image = fileObj._id.toString(); // don't need _.extend
// item should now be extended
Meteor.call('collectionInsert', item, function(error, result) {
if (error)
return alert(error.reason);
Router.go('collection', {_id: result._id});
});
});
}
By the way, you should probably store the result of $(value) instead of constructing the same jQuery object over and over. Just a minor optimization, but improves readability nonetheless.
var $value = $(value);
var item = {
name: $value.find('#name').val(),
...
};

Meteor method not returning ID to client

I am in the process of integrating stripe payments on my website, but I have run into a problem.
I want to transition the user to a dynamic route upon submitting the payments form (iframe supplied by stripe), but the Meteor method that I call on the client returns undefined instead of the ID of the newly inserted document that I wish to transition to
Any advice?
ERROR
Error: Missing required parameters on path "/purchases/:purchaseId". The missing params are: ["purchaseId"]. The params object passed in was: undefined.
client:
Template.viewTab.events({
'click #download': function(event) {
handler.open({
name: 'Tabr',
description: this.title,
amount: this.price
});
event.preventDefault();
},
});
var handler = StripeCheckout.configure({
key: '..............',
token: function(token) {
// Use the token to create the charge with a server-side script.
// You can access the token ID with `token.id`
tabId = Tabs.findOne()._id;
Meteor.call('makePurchase', tabId, token, function(error, purchaseId) {
if (error) {
console.log('makePurchaseError: ' + error);
FlashMessages.clear();
return FlashMessages.sendError(error.message, {
autoHide: true,
hideDelay: 10000
});
}
console.log(purchaseId);
Router.go('viewPurchase', purchaseId);
});
}
});
Server:
Meteor.methods({
/**
* [makePurchase attempts to charge the customer's credit card, and if succesful
* it inserts a new purchaes document in the database]
*
* #return {[String]} [purchaseId]
*/
makePurchase: function(tabId, token) {
check(tabId, String);
tab = Tabs.findOne(tabId);
Stripe.charges.create({
amount: tab.price,
currency: "USD",
card: token.id
}, Meteor.bindEnvironment(function (error, result) {
if (error) {
console.log('makePurchaseError: ' + error);
return error;
}
purchaseId = Purchases.insert({
sellerId: tab.userId,
tabId: tab._id,
price: tab.price
}, function(error, result) {
if (error) {
console.log('InsertionError: ' + error);
return error;
}
return result;
});
}));
console.log(purchaseId);
return purchaseId;
}
});

Resources