DynamoDB: Appending an element to a list using Node.js - javascript

This doesn't work. Is there another way to do this? cord is a list to which I want to add a map.
var params5 = {
TableName: 'rides',
Key: {
'rid': data2.Items[0].rid
},
UpdateExpression: 'add cord :x',
ExpressionAttributeValues: {
':x': [{date: secondStartDate.toString(), latitude: xcorpassed, longitude: ycorpassed}]
},
ReturnValues: 'UPDATED_NEW'
}
docClient.update(params5, function (err5, data5) { ... }

Instead of ADD, you could use SET with the list_append function (in general, AWS recommends using SET rather than ADD):
(NOTE: The list_append function name is case-sensitive)
var params = {
TableName: "rides",
Key: {
"rid": data2.Items[0].rid
},
UpdateExpression: "SET #c = list_append(#c, :vals)",
ExpressionAttributeNames: {
"#c": "cord"
},
ExpressionAttributeValues: {
":vals": [{date: secondStartDate.toString(), latitude: xcorpassed, longitude: ycorpassed}]
},
ReturnValues: "UPDATED_NEW"
}
docClient.update(params, function (err, data) {
if (err) console.log(err);
else console.log(data);
}

Without seeing the error code it throws it looks like you should change add to set and don't forget the = sign.
var params5 = {
TableName: 'rides',
Key: {
'rid': data2.Items[0].rid
},
UpdateExpression: 'set cord = :x',
ExpressionAttributeValues: {
':x': [{date: secondStartDate.toString(), latitude: xcorpassed, longitude: ycorpassed}]
},
ReturnValues: 'UPDATED_NEW'
}
docClient.update(params5, function (err5, data5) {

Related

Javascript Trasnact Write failing on increment item

I am trying to do a transact write in DynamoDB. I can't seem to see the error and the error says "validationError, none" which isn't particualarly helpful. The Put for sure works but I am keeping here for completeness in the example
await dynamoDb.transactWrite({
TransactItems: [
{
Put: {
TableName: process.env.TABLE_NAME,
Item: {
pk: compoundId,
sk: interest,
gsi1pk: "#INTEREST",
interest: interest,
id,
},
},
},
{
Update: {
ExpressionAttributeValues: {
":num": 1,
":initial": 0,
},
ExpressionAttributeNames: {
"#tally": "tally",
},
Key: {
PK: shop,
SK: interest,
},
TableName: process.env.TABLE_NAME,
UpdateExpression:
"SET #tally = if_not_exists(tally, :initial) + :num",
},
},
],
});
I'm fairly confident that this is doable per these similar solved questions here:
ItemCollectionMetrics is empty after successful transactWrite using DynamoDB.DocumentClient
Increment the value if it exists, else add a new entry in DynamoDB
The following appears to have worked and the error was adding the ExpressionAttributeNames
await dynamoDb.transactWrite({
TransactItems: [
{
Put: {
TableName: process.env.TABLE_NAME,
Item: {
pk: compoundId,
sk: interest,
gsi1pk: "#INTEREST",
watching: watching,
interest: interest,
id,
},
},
},
{
Update: {
ExpressionAttributeValues: {
":num": 1,
":initial": 0,
},
Key: {
pk: shop,
sk: interest,
},
TableName: process.env.TABLE_NAME,
UpdateExpression:
"SET tally = if_not_exists(tally, :initial) + :num",
},
},
],
});

Replace every name in a file by its google translation

I have a stations.js file that look like that :
module.exports = [
{
name: 'センター',
assetID: '01101010',
latitude: 43.062222,
longitude: 141.354167,
mongoID: 'b822dff1e50760b99248',
},
{
name: '北1条',
assetID: '01101520',
latitude: 43.062222,
longitude: 141.353889,
mongoID: '493062f76e253bd5cbe6',
},
...
]
I want to replace all the japanase names by their english translation from Google API (I haven't work on that yet for now let's say I want to replace them by a random work like "hello").
For example I want to rewrite my file like so :
module.exports = [
{
name: 'hello',
assetID: '01101010',
latitude: 43.062222,
longitude: 141.354167,
mongoID: 'b822dff1e50760b99248',
},
{
name: 'hello',
assetID: '01101520',
latitude: 43.062222,
longitude: 141.353889,
mongoID: '493062f76e253bd5cbe6',
},
...
]
That's the first time I do something like that and I'm pretty lost. For now my code looks like that :
const fs = require('fs');
function runScript() {
fs.readFile(process.argv[2], 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
fs.readFile(process.argv[3], 'utf8', function (err,logs) {
if (err) {
return console.log(err);
}
const newSta = {}
const rawNewSta = logs.match(/\s*name:\s*'(.*?)'/g)
rawNewSta.map(id => ({
name: id.split(`'`)[1],
})).forEach(station => newSta[station.name] = "hello")
console.log(newSta)
const splitFile = data.split(Object.keys(newSta))
let body = splitFile.reduce((acc, val) => `${acc}${val}name: '${readName(val, newSta)}',`, '')
body += splitFile.splice(-1)
// console.log("->", body)
fs.writeFile('stationsNew.js', body, function (err) {
if (err) return console.log(err);
console.log('stationNew.js created');
});
})
})
}
function readName(stationStr, newSta) {
const station = stationStr.match(/name:\s*['"](.*)['"],/g)
const name = station.splice(-1)[0].split(/name:\s*['"]/)[1].split(/['"],/)[0]
return newSta[name] ? newSta[name] : ''
}
You have an array of objects, so you can just work with it as an array of objects instead of doing all this string manipulation you're trying.
// in real life use `import` here
module = {}
module.exports = [
{
name: 'センター',
assetID: '01101010',
latitude: 43.062222,
longitude: 141.354167,
mongoID: 'b822dff1e50760b99248',
},
{
name: '北1条',
assetID: '01101520',
latitude: 43.062222,
longitude: 141.353889,
mongoID: '493062f76e253bd5cbe6',
}
]
for (item of module.exports) {
item.name = "hello" // or go get the translation here and substitute it in
}
console.log(module.exports) // in real life use fs.writeFile()

how do i select the longitude and latitude to return specific locations javascript

Okay, i have data from and xml file and have parsed it into a json object
which looks like this
1884 {
FHRSID: { '$t': '184564' },
LocalAuthorityBusinessID: { '$t': 'PI/000200989' },
BusinessName: { '$t': 'Zorba Grill Restaurant' },
BusinessType: { '$t': 'Restaurant/Cafe/Canteen' },
BusinessTypeID: { '$t': '1' },
AddressLine1: { '$t': '42 Market Place' },
AddressLine2: { '$t': 'Willenhall' },
AddressLine3: { '$t': 'Walsall' },
AddressLine4: { '$t': 'West Midlands' },
PostCode: { '$t': 'WV13 2AA' },
RatingValue: { '$t': '4' },
RatingKey: { '$t': 'fhrs_4_en-GB' },
RatingDate: { '$t': '2019-11-21' },
LocalAuthorityCode: { '$t': '433' },
LocalAuthorityName: { '$t': 'Walsall' },
LocalAuthorityWebSite: {
'$t': 'http://www.walsall.gov.uk/index/environment/food_production_and_quality.htm'
},
LocalAuthorityEmailAddress: { '$t': 'environmentalhealth#walsall.gov.uk' },
Scores: {
Hygiene: { '$t': '0' },
Structural: { '$t': '0' },
ConfidenceInManagement: { '$t': '10' }
},
SchemeType: { '$t': 'FHRS' },
NewRatingPending: { '$t': 'False' },
Geocode: {
Longitude: { '$t': '-2.05513900000000' },
Latitude: { '$t': '52.58389000000000' }
}
i would like to select a range between a certain longitude and a certain latitude but i can only manage to print one value or all values to the console,
my code looks like this
fs.readFile( "./FHRS433en-GB.xml", function(err, data) {
const xmlObj = xmlParser.toJson(data, {reversible: true, object: true})
const estDetail = xmlObj["FHRSEstablishment"]['EstablishmentCollection']['EstablishmentDetail']
const objProps = (obj) => {
for (let val in obj) {
console.log(val, obj[val]);
};
};
for (let i=0;i < estDetail.length;i++) {
let lonGitude = estDetail[i]['Geocode']['Longitude'];
let laTitude = estDetail[i]['Geocode']['Latitude'];
if (laTitude <= 52.5876183 && Latitude >= 52.5756329) {
// console.log(estDetail);
}
}
objProps(estDetail);
});
i dont know how to go about selecting the information i want when the output has
Latitude: { '$t': '52.58389000000000' } in front im not sure if it changes how i am meant to call the data.
anything would be helpful
also i have require(fs) and (xml2json) just as a side note
xml2json writes the text attributes if not configured otherwise in $t keys. You should also use parseFloat to convert the strings.
for (let i = 0; i < estDetail.length; i++) {
let longitude = parseFloat(estDetail[i]["Geocode"]["Longitude"]["$t"]);
let latitude = parseFloat(estDetail[i]["Geocode"]["Latitude"]["$t"]);
if (latitude <= 52.5876183 && latitude >= 52.5756329) {
console.log(estDetail);
}
}

append to list if exist or add list in dynamoDB

I have a product table in DynamoDB which has some items. Now I need to add list of buyers to the product which can grow i.e. append to list. It works for if I have an empty list or a list with some items in the table item but for the first addition it throws an error. Is there any way to check if list exists then append else add a list. here is my code
let params = {
TableName: "product",
ExpressionAttributeNames: {
"#Y": "buyer"
},
ExpressionAttributeValues: {
":y": ["PersonXYZ"]
},
Key: {
id: 'Hy2H4Z-lf'
},
UpdateExpression: "SET #Y = list_append(#Y,:y)"
};
updateItemInDDB(params).then((data) => {
res.status(200).send(data);
}, err => {
console.log(err);
res.sendStatus(500);
});
UpdateItemInDDB is just a function which takes a params and run dnamodb code on it. I am using javascript sdk for DynamoDB with Document Client.
var params = {
TableName: "user",
Key: {
"user_id": {
S: user_id
}
},
UpdateExpression: "SET #ri = list_append(if_not_exists(#ri, :empty_list), :vals)",
ExpressionAttributeNames: {
"#ri": "images"
},
ExpressionAttributeValues: {
":vals": {"L": [{
"S": "dummy data"
}]},
":empty_list": {"L": []}
},
ReturnValues: 'ALL_NEW'
};
":empty_list": {"L": []}
this is important if you want to set empty list, otherwise it will give below exception.
"errorMessage": "ExpressionAttributeValues contains invalid value: Supplied AttributeValue is empty, must contain exactly one of the supported datatypes for key :empty_list",
"errorType": "ValidationException"
EDIT: Nest the conditional expressions
You could run SET append_list with a ConditionalExpression that the attribute does exist, then if that fails run SET with a ConditinalExpression that the attribute does not exist.
let params1 = {
TableName: "product",
ExpressionAttributeNames: {
"#Y": "buyer"
},
ExpressionAttributeValues: {
":y": ["PersonXYZ"]
},
Key: {
id: 'Hy2H4Z-lf'
},
ConditionExpression: "attribute_exists(buyer)",
UpdateExpression: "SET #Y = list_append(#Y,:y)"
};
updateItemInDDB(params1).then((data) => {
res.status(200).send(data);
}, err => {
console.log(err);
let params2 = {
TableName: "product",
ExpressionAttributeNames: {
"#Y": "buyer"
},
ExpressionAttributeValues: {
":y": ["PersonXYZ"]
},
Key: {
id: 'Hy2H4Z-lf'
},
ConditionExpression: "attribute_not_exists(buyer)",
UpdateExpression: "SET #Y = (#Y,:y)"
};
updateItemInDDB(params2).then((data) => {
res.status(200).send(data);
}, err => {
console.log(err);
res.sendStatus(500);
});
});

How to access data on a `through` table with Bookshelf

I am using [BookshelfJS][bookshelfjs] for my ORM and am wondering how to access data on a though table.
I have 3 Models, Recipe, Ingredient and RecipeIngredient which joins the two.
var Recipe = BaseModel.extend({
tableName: 'recipe',
defaults: { name: null },
ingredients: function () {
return this
.belongsToMany('Ingredient')
.through('RecipeIngredient')
.withPivot(['measurement']);
}
}));
var Ingredient = BaseModel.extend({
tableName: 'ingredients',
defaults: { name: null },
recipes: function () {
return this
.belongsToMany('Recipe')
.through('RecipeIngredient');
}
}));
var RecipeIngredient = BaseModel.extend({
tableName: 'recipe_ingredients',
defaults: { measurement: null },
recipe: function () {
return this.belongsToMany('Recipe');
},
ingredient: function () {
return this.belongsToMany('Ingredient');
}
}));
I then attempt to retrieve a Recipe along with all the Ingredients however cannot work out how to access measurement on the RecipeIngredient.
Recipe
.forge({
id: 1
})
.fetch({
withRelated: ['ingredients']
})
.then(function (model) {
console.log(model.toJSON());
})
.catch(function (err) {
console.error(err);
});
Return:
{
"id": 1,
"name": "Delicious Recipe",
"ingredients": [
{
"id": 1,
"name": "Tasty foodstuff",
"_pivot_id": 1,
"_pivot_recipe_id": 1,
"_pivot_ingredient_id": 1
}
]
}
With no measurement value.
I had thought that the .withPivot(['measurement']) method would have grabbed the value but it does not return any additional data.
Have I missed something or misunderstood how this works?
I'm not exactly sure why you want to use through. If it's just a basic many-to-many mapping, you can achieve this by doing the following:
var Recipe = BaseModel.extend({
tableName: 'recipe',
defaults: { name: null },
ingredients: function () {
return this
.belongsToMany('Ingredient').withPivot(['measurement']);
}
}));
var Ingredient = BaseModel.extend({
tableName: 'ingredients',
defaults: { name: null },
recipes: function () {
return this
.belongsToMany('Recipe').withPivot(['measurement']);;
}
}));
You don't need an additional model for junction table. Just be sure to define a junction table in your database as ingredients_recipe (alphabetically joining the name of tables!). Or , you can provide your own custom name to belongsToMany function for what the junction table should be named. Be sure to have ingredients_id and recipe_id in ingredients_recipe
This is pretty much it. Then you can do
Recipe
.forge({
id: 1
})
.fetch({
withRelated: ['ingredients']
})
.then(function (model) {
console.log(model.toJSON());
})
.catch(function (err) {
console.error(err);
});

Categories

Resources