Ionic project with database - angularjs

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.

Related

Cypress 10 and connecting to an Oracle database

So I've got a new Cypress 10 project, and I'm trying to integrate some functionality to allow me to make some basic database calls to our Oracle database (which is on a server I have direct access to, not running locally).
I've been following this guide which shows how to add the oracledb package as a Cypress plugin, but the method used (using the /plugin directory) has been depreciated in Cypress 10 so I can't follow the example exactly.
I've instead tried applying this logic using the Cypress plugin documentation as a guide and I think I have something that almost works, but I can't seem to connect to any database, even if the location is in my tnsnames.ora file (although I'm providing the connection string directly for this particular project).
Here's what my cypress.config.ts file looks like, with the code I've created (I'm using Cucumber in my implementation too, thus why those references are present here):
import { defineConfig } from "cypress";
import createBundler from "#bahmutov/cypress-esbuild-preprocessor";
import { addCucumberPreprocessorPlugin } from "#badeball/cypress-cucumber-preprocessor";
import createEsbuildPlugin from "#badeball/cypress-cucumber-preprocessor/esbuild";
const oracledb = require("oracledb");
oracledb.initOracleClient({ libDir: "C:\\Users\\davethepunkyone\\instantclient_21_6" });
// This data is correct, I've obscured it for obvious reasons
const db_config = {
"user": "<username>",
"password": "<password>",
"connectString": "jdbc:oracle:thin:#<hostname>:<port>:<sid>"
}
const queryData = async(query, dbconfig) => {
let conn;
try{
// It's failing on this getConnection line
conn = await oracledb.getConnection(dbconfig);
console.log("NOTE===>connect established")
return await conn.execute(query);
}catch(err){
console.log("Error===>"+err)
return err
} finally{
if(conn){
try{
conn.close();
}catch(err){
console.log("Error===>"+err)
}
}
}
}
async function setupNodeEvents(
on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions ): Promise<Cypress.PluginConfigOptions> {
await addCucumberPreprocessorPlugin(on, config);
on("file:preprocessor", createBundler({
plugins: [createEsbuildPlugin(config)],
})
);
on("task", {
sqlQuery: (query) => {
return queryData(query, db_config);
},
});
return config;
}
export default defineConfig({
e2e: {
specPattern: "**/*.feature",
supportFile: false,
setupNodeEvents,
},
});
I've then got some Cucumber code to run a test query:
Then("I do a test database call", () => {
// Again this is an example query for obvious reasons
const query = "SELECT id FROM table_name FETCH NEXT 1 ROWS ONLY"
cy.task("sqlQuery", query).then((resolvedValue: any) => {
resolvedValue["rows"].forEach((item: any) => {
console.log("result==>" + item);
});
})
})
And here are the dependencies from my package.json:
"dependencies": {
"#badeball/cypress-cucumber-preprocessor": "^12.0.0",
"#bahmutov/cypress-esbuild-preprocessor": "^2.1.3",
"cypress": "^10.4.0",
"oracledb": "^5.4.0",
"typescript": "^4.7.4"
},
I feel like I'm somewhat on the right track as when I run the feature step above, the error I get back is:
Error===>Error: ORA-12154: TNS:could not resolve the connect identifier specified
This makes me think that it has at least called the node-oracledb package to generate the error but I can't really tell if I've made an obvious error or not (I'm pretty new to JS/TS). I know I've referenced the right path for the oracle instant client and it's been initialized correctly at least because Cypress points out a config error if the path is incorrect. I know the database paths work as well because we have an older Selenium implementation that can connect using the details I'm providing.
I think I'm just more curious to know if anyone has so far successfully implemented an oracledb connection with Cypress 10 or if someone who has a bit more Cypress experience can spot any obvious errors in my code as resources for this particular combination of packages seem to be non-existent (possibly because Cypress 10 is reasonably new).
NOTE: I am planning on switching to using environmental variables for the database connection information that will eventually be passed into the project - I just want to get a connection working first before I tackle that issue.
Oracle's C stack drivers like node-oracledb are not using Java so the JDBC connection string needs changing from:
"connectString": "jdbc:oracle:thin:#<hostname>:<port>:<sid>"
If you were using:
jdbc:oracle:thin:#mydbmachine.example.com:1521/orclpdb1
then your Node.js code should use:
connectString : "mydbmachine.example.com:1521/orclpdb1"
Since you're using the very obsolete SID syntax, check the node-oracledb manual for the solution if you can't use a service name: JDBC and Oracle SQL Developer Connection Strings.

test database for react-native app development

I'm in the early stages of developing an app with react-native, and I need a DB implementation for for testing and development. I thought that the obvious choice would be to use simple JSON files included with the source, but the only way I see to load JSON files requires that you know the file name ahead of time. This means that the following does not work:
getTable = (tableName) => require('./table-' + tableName + '.json') // ERROR!
I cannot find a simple way to load files at runtime.
What is the proper way to add test data to a react-native app?
I cannot find a simple way to load files at runtime.
In node you can use import() though I'm not sure if this is available in react-native. The syntax would be something like:
async function getTable(tableName){
const fileName = `./table-${tableName}.json`
try {
const file = await import(fileName)
} catch(err){
console.log(err
}
}
though like I said I do not know if this is available in react-natives javascript environment so ymmv
Unfortunately dynamic import not supported by react-native but there is a way so to do this
import tableName1 from './table/tableName1.json';
import tableName2 from './table/tableName2.json';
then create own object like
const tables = {
tableName1,
tableName2,
};
after that, you can access the table through bracket notation like
getTable = (tableName) => tables[tableName];

Use a .db file with MS Chatbot

Here is my situation : I'm developing a Chatbot on Microsoft azure platform using Node.js. For the moment the bot messages are hard-coded in .json files.
I want to improve it by using calls to a database.
I have a SQLite database file working fine (I used a browser for SQLite and made my requests). But the problem is :
How do can I use my .db file from my project ? Is this possible to somehow "read" the database file from my dialogs and then make my request to get what I need from my database ?
I know that you can call a database with the chatbot, but the issue here is that I only have the file and nothing deployed to call.
Example of what the result should give :
"Hey chatbot, tell me about Mona Lisa"
This triggers the dialogs that will ask the database : "SELECT info FROM arts WHERE arts.title LIKE '%Mona Lisa%' ";
And send the result in session.send(results).
Thanks !
Note : I'm just an intern in my company, the database file is the only thing they gave me and I have to find a solution with it
I got the solution after some research :
First you need to install sqlite3 with npm for example, then use this at the beginning of your code :
var sqlite3 = require('sqlite3').verbose();
var path = require('path');
var db_path = path.resolve(__dirname, name_Of_Your_DB);
And then work on your file with the request you need :
var db = new sqlite3.Database(db_path, sqlite3.OPEN_READONLY,(err) => {
if (err) {
return console.error(err.message);
}
//console.log("Stuff that is processed only if no error happened.");
});
var req = "YOUR REQUEST";
db.get(req, [your_parameter],(err, row) => {
if (err) {
return console.error(err.message);
}
});
db.close((err) => {
if (err) {
return console.log(err.message);
}
});
The documentation about node.js and sqlite3 is quite complete :
http://www.sqlitetutorial.net/sqlite-nodejs/query/

React Native - How to connect to AWS DynamoDB table

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
});

Mapping relational MongoDB data in website : help needed

I run an Android app which locates OBJECTS with attributes like ID, Name, Owner, Type, Place_ID which are linked to PLACES, on a map. PLACES have attributes like ID, Latitude, Longitude, Opening Hour, Closing Hour,... The data is stored in a MongoDB on Back4App and I want to keep that way. I have one class for OBJECTS and one class for PLACES. The relation between OBJECTS and PLACES is not "a MongoDB relation", it is just a common String field in the OBJECTS and PLACES classes.
In order to allow offline access to the data and to minimize DB server requests, the app synchronizes a local SQLITE database on the device with the MongoDB online database. In the Android App, the queries are passed to the SQLITE DB.
I'm trying to make a website which does the same job as the app, which is displaying filtered data from the MongoDB.
I started with a simple html and javascript website using the Parse SDK, but I'm facing a few difficulties.
A simple query is to list all the OBJECTS in a 50km radius, i.e. I need the OBJECTS and the PLACE where they are located. However, where I could get this easilty with a SELECT...JOIN in SQLITE, I cannot get this information through a simple Parse query because I want to know the OBJECTS too. And I cannot run 2 asynchronous queries in a for loop.
What website architecture and/or languages would you recommend for this type of website ?
How would you recommend to proceed ?
Thanks in advance for your help.
EDIT: ZeekHuge opened my eyes on the bad design of not using pointers. After implementing pointers in my MongoDB, here's the lines of codes which did it for me :
Parse.initialize("", "");
Parse.serverURL = '';
var eiffel = new Parse.GeoPoint(48.858093, 2.294694);
var myScores = '';
var Enseigne = Parse.Object.extend("ENSEIGNE");
var Flipper = Parse.Object.extend("FLIPPER");
var query = new Parse.Query(Flipper);
var innerquery = new Parse.Query(Enseigne);
innerquery.withinKilometers("ENS_GEO",eiffel,500);
query.equalTo("FLIP_ACTIF", true);
query.include("FLIP_ENSPOINT");
query.include("FLIP_MODPOINT");
query.matchesQuery("FLIP_ENSPOINT", innerquery);
query.find({
success: function(results) {
for (var i = 0; i < results.length; i++) {
var object = results[i];
myScores += '<tr><td>' + object.get('FLIP_MODPOINT').get('MOFL_NOM')
+ '</td><td>' + object.get('FLIP_ENSPOINT').get('ENS_NOM')
+ '</td><td>' + object.get('FLIP_ENSPOINT').get('ENS_GEO').latitude
+ '</td><td>' + object.get('FLIP_ENSPOINT').get('ENS_GEO').longitude
+ '</td></tr>';
}
(function($) {
$('#results-table').append(myScores);
})(jQuery);
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
Solved by replacing the database keys by pointers and using the Innerquery and include functions. See exemple mentionned in question.

Resources