React Native - How to connect to AWS DynamoDB table - reactjs

I am following this aws tutorial to create my first React Native app which connects to AWS:
aws tutorial
Everything installs fine and my app runs happily with the following imports:
**import Amplify from 'aws-amplify';
import aws_exports from './aws-exports';
Amplify.configure(aws_exports);**
I would now like to connect the app to an existing DynamoDB table called 'Movement' but the tutorial only shows how to create a new table with the NoSQL wizard using: awsmobile database enable --prompt
Could you point me to a (simple) resource that shows me how to connect to an existing DynamoDB table and perform CRUD operations?
These are the steps I have followed:
I have a DynamoDB table called: movement
It has 3 items : hub_id, on_time, message
Hub_id is the primary partition key
on_time is the primary sort key
The table holds sensor data (movement, temperature that sort of thing) in the message item.
I created the app using :
create-react-native-app dbapp
I have then run:
awsmobile configure
aws mobile init
Installed amplify:
npm install aws-amplify --save
I created the project in mobile hub.
I then linked the app to the hub using:
awsmobile init 15c482e2-2c3c-11e8-8692-fblahblahblah3
CLI responded : Successfully linked AWS Mobile Hub project: dbapp-datetime!
So all looks good so far (I hope!)
I then altered app.js to look like this: pastebin
npm start runs just fine with no errors that I can see.
The problem that I currently have is that I don't have a clue about how to query my table and populate variables so that I can use them in the view.

Following the resources suggested (thanks SteveB). I connected to the DynamoDB table, queried it and used the data in my app.
In case you are also stuck, here is an edited version of my code. Apologies to everyone that gets to edit this - I know it is awful. Does work though :)
// Use db to query the dynamoDB table - setup query parameters first //
var params = {
TableName : "myproject-mobilehub-123456789-Sensors",
ProjectionExpression:"hub_id, details.on_time, details.sensor_name,
details.temperature, details.battery",
KeyConditionExpression: "hub_id = :hid AND begins_with(on_time, :d)",
ExpressionAttributeValues: {
":hid":"testdevice01",
":d": today,
},
Limit: 1,
ScanIndexForward: false
};
//Execute db query using params
async getQuery() {
db.query(params, function(err, data) {
if (err) { console.log("Query failed.");
} else {
console.log("Query succeeded.");
};
data.Items.forEach(function(details) {
//display variables
console.log(details.hub_id,details.details.sensor_name,details.details.on_time,
details.details.temperature, details.details.battery,);
//Populate variables
hubid = details.hub_id;
currroom = details.details.sensor_name;
roomtime = details.details.on_time;
roomtemp = details.details.temperature;
roombattery = details.details.battery + "%";
});
}});
//Finally populate text with variables
this.setState({
displayText1: currroom,
displayText2: roombattery,
displayText3: roomtime,
displayText4: roomtemp
});

Related

AWS Amplify - updating a column in a DynamoDB

I am trying to figure out how to update a colums in a Dynamo table, using the 'aws-amplify' API.
Without Amplify, (just using the AWS SDK), that could be done like this:
const docClient = new AWS.DynamoDB.DocumentClient();
let params = {
TableName:table,
Key:{
"year": year,
"title": title
},
UpdateExpression: "set info.rating = :r, info.plot=:p, info.actors=:a",
ExpressionAttributeValues:{
":r":5.5,
":p":"Everything happens all at once.",
":a":["Larry", "Moe", "Curly"]
},
ReturnValues:"UPDATED_NEW"
};
docClient.update(params, function(err, data) { ....
I set up a backend/api using the docs here to ( enable cloud API to do CRUD operations)
https://docs.aws.amazon.com/aws-mobile/latest/developerguide/web-access-databases.html
Everything works fine as far as 'put/get' methods that create new records,etc
import Amplify, { API } from 'aws-amplify';
....
const path = '/MyTable';
const newRecord = {.......}
const apiResponse = await API.put('MyTableCRUD', path, newRecord);
But there is so little documentation on more advanced techniques like the update above, that I don't know how if/how this can be achieved using Amplify.
Hoping someone has already done this!
Thank you
You can create a custom route in the cloud API of your database (which is usually located under awsmobilejs/backend/cloud-api/INSERT_TABLE_NAME). Unless you modified the cloud API of your database in the past, the main file where all of the routes of the API are specified should be awsmobilejs/backend/cloud-api/INSERT_TABLE_NAME/app.js, or in your case awsmobilejs/backend/cloud-api/MyTable/app.js.
For more information about creating custom routes in your cloud API and some examples, check out the example app's cloud API and the express API reference.

Ionic 3 I can't call data with SQLite

I am using SQLite on the project. I perform events like insert operations in database operations successfully. But I do not know how to reach the data when it brings the data. I am trying to create a list of the following code fragment. I'm waiting for your help.
GRUPLISTESI : any;
GRUPLAR(){
var sql = "SELECT * FROM 'GRUPLAR'";
this.db.executeSql(sql, {}).then((data)=>{
this.GRUPLISTESI = data["rows"]; //What should I write here?
});
}
You can access the data from your Ionic sqlite database like this:
db.executeSql("SELECT * FROM test")
.then(result => {
console.log(result.rows.item(0).id);
});
So abstract it would look like so: result.rows.item([row]).[column_label].
For some deeper examples on how to use sqlite for Ionic, you can use this repository: https://github.com/didinj/ionic3-angular4-cordova-sqlite-example

CloudKit Database Query Issue

I just started to build a web app, and for some reason I have to use CloudKit and its database for my backend.
I tried a really stupid database query and intended to see the results at frontend. Here is my code :
CloudKit.configure({
containers: [{
containerIdentifier: my identifier,
apiToken: my api token,
environment: 'development'
}]
});
var container = CloudKit.getDefaultContainer();
var DB = container.publicCloudDatabase;
var query = {recordType : 'Request'};
DB.performQuery(query).then(function(response){
if (response.hasErrors) {
throw response.errors[0];
} else {
console.log(response);
}
});
However, I keep getting this authentication_failed error :
cloudkit.js:3 Uncaught (in promise) t {_ckErrorCode: "AUTHENTICATION_FAILED", _uuid: "4ef8ba12-eb00-408f-9a1c-6e8b4de84ec8", _reason: "no auth method found", _serverErrorCode: "AUTHENTICATION_FAILED", _extensionErrorCode: undefined…}
I tried to fetch a record with the same code, and it works fine.
So is the error caused by unlogged in users? If so, Is there any configurations in CloudKit Dashboard to allow users from certain URL to query the database without logging in?
Thanks!
Check the containerIdentifier value. I had a similar issue when I used the identifier name of the API Token instead of the generated iCloud identifier from the app name. You can also verify your token with the link Test with CloudKit Catalog

Ionic project with database

I am trying to create a mobile project , which is my first project in Ionic platform.
for same , I have to learn Angular and Ionic. So I decided to make a simple mobile project.
I have googled too much for Database in mobile technology so I got many of database like- MongoDb, SQLite, Firebase etc. so I was the bit confused about which database should I use in the ionic mobile project?
And Is there any beginners documentation for any database that helps me to implement the database in my ionic project?
Thank you so much.
Instead of try to get it all at once, for training purposes, I would suggest starting only with Angular itself. Then, on a second project, try Ionic.
Some good starting points for angular are:
https://www.codecademy.com/pt-BR/learn/learn-angularjs
http://www.learn-angular.org/
Then, for Ionic I used:
https://thinkster.io/ionic-framework-tutorial
Now, specifically about database:
Ionic works with cordova, which maker the link between web development and mobile native functions. It makes it through plugins.
Nativelly Android and IOS support SQLite. So, if you want to use the most native resources possible, I think SQLite is the best option.
The best plugin (IMHO) is https://github.com/litehelpers/Cordova-sqlite-storage.
It's very easy to use this plugin:
On a Ionic cordova project, run
cordova plugin add cordova-sqlite-storage
Then, in your code, access the DB with
var db = window.sqlitePlugin.openDatabase({name: 'my.db', location: 'default'}, successcb, errorcb);
Then, simply run your SQLs:
db.executeSql("select length('tenletters') as stringlength", [], function (res) {
var stringlength = res.rows.item(0).stringlength;
console.log('got stringlength: ' + stringlength);
document.getElementById('deviceready').querySelector('.received').innerHTML = 'stringlength: ' + stringlength;
});
On the plugin site, there are more completes examples.
But, once again, I suggest learn the peaces first.
EDIT
Responding to comment:
To add information on Database is simple, almost like the SELECT sample above. Just pass your data as an array, on 2º argument of executeSQL(). Like this:
db.executeSql('INSERT INTO MyTable VALUES (?)', ['test-value'], function (resultSet) {
console.log('resultSet.insertId: ' + resultSet.insertId);
console.log('resultSet.rowsAffected: ' + resultSet.rowsAffected);
}, function(error) {
console.log('SELECT error: ' + error.message);
});
Take a look at the documentation, there are others examples there.
I have been swimming through article after article of "not quite what I am looking for" answers. I found a video in french. Here it is: Ionic 3 Store Data
That being said, here is how to setup your code to make ionic 3 cordova sqlite workable.
1) Import your native sqlite by running these 2 commands in your npm or cmd prompt.
ionic cordova plugin add cordova-sqlite-storage
npm install --save #ionic-native/sqlite
2) Import into your app.module.ts
import { SQLite} from '#ionic-native/sqlite';
3) Add as a provider in your app.module.ts
providers: [
...
SQLite,
...
]
4) Create a new folder(if you want to make it a different component) and make a database ts file. For the sake of ease I called mine database.ts
5) Add the following code (Please note this is not real code that I use. Just an example. Usernames and passwords should not be stored in this way):
import { Injectable } from '#angular/core';
import { SQLite, SQLiteObject } from '#ionic-native/sqlite';
#Injectable()
export class Database {
theConsole: string = "Console Messages";
options: any = {
name: data.db,
location: 'default',
createFromLocation: 1
}
private db: SQLiteObject;
constructor(private sqlite: SQLite) {
this.connectToDb();
}
private connectToDb():void {
this.sqlite.create(this.options)
.then((db: SQLiteObject) => {
this.db = db;
var sql = 'create table IF NOT EXISTS `user` (username VARCHAR(255), password VARCHAR(255))';
//IF you move the below statment out of here then the db variable will not be initialized
//before you can use it to execute the SQL.
this.db.executeSql(sql, {})
.then(() => this.theConsole += 'Executed SQL' + sql)
.catch(e => this.theConsole += "Error: " + JSON.stringify(e));
})
.catch(e => this.theConsole += JSON.stringify(e));
}
addUser(username, password):void {
var sql = "INSERT INTO `user` (username,password) VALUES ('"+username+"','"+ password+"')";
this.db.executeSql(sql,{})
.then(() => this.theConsole += "\n" + 'Executed SQL' + sql)
.catch(e => this.theConsole += "Error: " + JSON.stringify(e));
}
getDealer() {
var sql = "SELECT * FROM user";
this.db.executeSql(sql, {})
.then((result) => {
this.theConsole += JSON.stringify(result);
if (result.rows.length > 0) {
this.theConsole += 'Result' + result.rows.item(0);
}
this.theConsole += "\n" + result.rows.item(0).username+ result.rows.item(0).password;
this.theConsole += "\n" +'Rows' + result.rows.length;
})
.catch(e => this.theConsole += JSON.stringify(e));
}
getConsoleMessages() {
return this.theConsole;
}
}
Then you just have to import the database component(Class) into one of your pages and you can access the database by running these functions or by making your own RunSQL function that you can throw whatever you want into it.
What is really the part that confused me from ionic's website was the fact that they were showing the create but not the reuse of the SQLiteObject.
By adding the:
private db: SQLiteObject;
to my code in the declaration of class variables and in the initializing of the db object:
...
this.sqlite.create(this.options)
.then((db: SQLiteObject) => {
this.db = db;
...
I was able to reuse the db variable without having to open the db connection over and over again.
6) Import your component class into a page
import { Database } from '../../data/database';
I used this site: ionic native sqlite to get the main understanding of how to set it up and the french video mentioned earlier. I wish I would have found I hopefully can help others hitting this same sqlite wall. I wish I would have found what I found today sooner. I hopefully can help others hitting this same sqlite wall.

Hosting nodeJS app with firebase

So I have this web-app using angularJS and nodeJS. I don't want to just use localhost to demo my project because it doesn't looks cool at all when I type "node server.js" and then go to localhost.....
Since I intend to use Firebase for the data, I have noticed that Firebase provides hosting. I tried it, but it seems to only host the index.html and not through/using server.js. I have customized files for the server to use/update. So, how can I tell Firebase Hosting to use my server and related files when hosting?
Is it possible to tell Firebase, hey, run "node server.js" to host my index.html?
I'm guessing by the way you are wording the question you want to see this site from "the internet".
Two routes you could go here.
a) Serve your index through Firebase hosting. Firebase only hosts assets. If your Angular app is being served through Node then you will need to change your architecture to be more SPA-ish
SPA-ish would be like an index bootstrap that interacts with the backend purely through API's.
You would host the API server on something more appropriate like through Nodejitsu.
b) Serve the whole thing through something like Nodejitsu (hosting platform) or your very own VM managed by a different kind of hosting company like BuyVM.net.
Another idea, is if your nodejs app is independent of the angularjs app (however they use shared data, and perform operations on that data model) you could separate the two and connect them only via firebase.
Firebase hosting -> index.html and necessary angularjs files.
Locally (your PC) -> server.js which just connects to firebase and trigger on changed data.
I have done this for a few projects and it's a handy way to access the outside world (internet) while maintaining some semblence of security by not opening ports blindly.
I was able to do this to control a chromecast at my house while at a friends house
Here's an example from my most recent project (I'm trying to make a DVR).
https://github.com/onaclov2000/webdvr/blob/master/app.js
var FB_URL = '';
var Firebase = require('firebase');
var os = require('os')
var myRootRef = new Firebase(FB_URL);
var interfaces = os.networkInterfaces();
var addresses = [];
for (k in interfaces) {
for (k2 in interfaces[k]) {
var address = interfaces[k][k2];
if (address.family == 'IPv4' && !address.internal) {
addresses.push(address.address)
}
}
}
// Push my IP to firebase
// Perhaps a common "devices" location would be handy
var ipRef = myRootRef.push({
"type": "local",
"ip": addresses[0]
});
myRootRef.on('child_changed', function(childSnapshot, prevChildName) {
// code to handle child data changes.
var data = childSnapshot.val();
var localref = childSnapshot.ref();
if (data["commanded"] == "new") {
console.log("New Schedule Added");
var schedule = require('node-schedule');
var date = new Date(data["year"], data["month"], data["day"], data["hh"], data["mm"], 0);
console.log(date);
var j = schedule.scheduleJob(date, function(channel, program, length){
console.log("Recording Channel " + channel + " and program " + program + " for " + length + "ms");
}.bind(null, data["channel"], data["program"], data["length"]));
localref.update({"commanded" : "waiting"});
}
});
When I change my "commanded" data at the FB_URL, to "new" (which can be accomplished by angularjs VERY Simply, using an ng-click operation for example) it'll schedule a recording for a particular date and time (not all actually functional at the moment).
I might be late but since 3 years have passed there is an solution available now from Firebase in the form of cloud functions
Its not straight forward but looks promising if one can refactor their code a bit

Resources