Arngodb, Arangojs error while retriving data - arangodb

I get this error when trying to retrieve data from arangodb.
TypeError: db.database is not a function
var Database = require('arangojs');
var db = new Database({url:'http://127.0.0.1:8529'});
module.exports = {
getAllUsers : function()
{
return db.database('superrango')
.then(function (mydb) {return mydb.query('FOR x IN Users RETURN x');})
.then(function (cursor) { return cursor.all();});
}
}

Finally cracked it
var arangojs = require("arangojs");
var db = new arangojs.Database('http://127.0.0.1:8529');
db.useDatabase("superrango");
db.useBasicAuth("root", "asdf");
module.exports = {
getAllUsers : function()
{
return db.query('FOR x IN Users RETURN x')
.then((value) => {return value.all();});
}
}

Related

How to call another prototype async function from another in the same class

I have one async prototype function and that is called from another async prototype function. But, I got the error below. How to resolve?
I use node.js v14.1.0.
UnhandledPromiseRejectionWarning: TypeError: this.saySomething2 is not a function
const Person = function() {
console.log("CALLED PERSON");
};
Person.prototype.saySomething = async function() {
this.saySomething2();
};
Person.prototype.saySomething2 = async function() {
//do something
console.log("hello");
};
(async function() {
var ape = new Person();
await ape.saySomething();
}());
update: adding actual code.
// constructor function for the KingInfo class
function KingInfo(
date,
employeeKey,
workDayTypeName) {
this._date = date;
this._employeeKey = employeeKey;
this._workDayTypeName = workDayTypeName;
}
KingInfo.prototype.sync = async function(){
var isSucceed = false;
let syncType = await this.getSyncType();
if(syncType === "post"){
}
else if(syncType === "patch"){
}
else{
}
return isSucceed;
}
//#return: "post", "patch", "none"
KingInfo.prototype.getSyncType = async function(){
let syncType = "none";
let sql = [];
sql.push("SELECT count(*) as count");
...
let records = await db_module.query(sql.join(""));
let count = records[0].count;
if(count <= 0){
syncType = "post";
}
else{
let isSame = await this.compareToDataInDB();
if(!isSame){
syncType = "patch";
}
}
return syncType;
}
KingInfo.prototype.compareToDataInDB = async function(){
let date = this._date;
let empKey = this._employeeKey;
let sql = [];
sql.push("SELECT workDayTypeName");
...
let records = await db_module.query(sql.join(""));
let record = records[0];
let res = false;
if(workDayTypeName === record.workDayTypeName){
res = true;
}
return res;
}
(async function(){
let date = "2020-08-01";
let employeeKey = "";
let workDayTypeName = "aaaaa";
let kingInfo = new KingInfo(
date,
employeeKey,
workDayTypeName);
kingInfo.sync();
}());
module.exports = {
KingInfo: KingInfo
}
I got this error:
UnhandledPromiseRejectionWarning: TypeError: Cannot read property '_date' of undefined
UnhandledPromiseRejectionWarning: TypeError: this.compareToDataInDB is not a function
update:
adding code for db module.
this module might effect badlly?
db.js
"use strict";
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
database: 'something'
});
function query(sql){
return new Promise(function(resolve, reject) {
connection.connect((err) => {
if (err) throw err;
connection.query(sql, function (err, result, fields) {
if (err) throw err;
resolve(result);
});
});
});
}
module.exports = {
query: query
}

Vector Tiles for MapboxGL Client doesnt return properties

I am trying to set up a web server in Node.js that serves vector tiles to be displayed in a browser using MapboxGL JS. The data for the vector tiles is stored in a PostGIS database.
this is my database scheme: CREATE TABLE IF NOT EXISTS earthquakes( table_id SERIAL, properties jsonb not null, geom geometry(GeometryZ,4326), primary key (table_id));
earthquakes has properties inside the geojson and I store each feature in database.
For example, earthquakes has this properties: "properties": { "id": "ak16994521", "mag": 2.3, "time": 1507425650893, "felt": null, "tsunami": 0 }. You can see all geojson here.
My current set up seems to going in the right direction, as I can see vector tiles being loaded and displayed in the browser, and the rendered result is correct.
However, when I click on a feature only return table_id and dont return properties of each feature.
How can send properties???
var zlib = require('zlib');
var express = require('express');
var mapnik = require('mapnik');
var Promise = require('promise');
var SphericalMercator = require('sphericalmercator');
var mercator = new SphericalMercator({
size: 256 //tile size
});
mapnik.register_default_input_plugins();
var app = express();
app.get('/:namelayer/:z/:x/:y.pbf', (req, res, next) => {
var options = {
x: parseInt(req.params.x),
y: parseInt(req.params.y),
z: parseInt(req.params.z),
layerName: req.params.namelayer
};
makeVectorTile(options).then( (vectorTile) => {
zlib.deflate(vectorTile, (err, data) => {
if (err) return res.status(500).send(err.message);
res.setHeader('Content-Encoding', 'deflate');
res.setHeader('Content-Type', 'application/x-protobuf');
return res.send(data);
});
});
});
function makeVectorTile(options) {
var extent = mercator.bbox(options.x, options.y, options.z, false, '3857');
var map = new mapnik.Map(256, 256, '+init=epsg:3857');
map.extent = extent;
var layer = new mapnik.Layer(options.layerName);
layer.datasource = new mapnik.Datasource({
type: process.env.DB_TYPE,
dbname: process.env.DB_DATABASE,
table: options.layerName,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD
});
layer.styles = ['default'];
map.add_layer(layer);
return new Promise( (resolve, reject) => {
var vtile = new mapnik.VectorTile(parseInt(options.z), parseInt(options.x), parseInt(options.y));
map.render(vtile, function (err, vtile) {
if (err) return reject(err);
console.log(`${vtile.getData().length} KB`);
resolve(vtile.getData());
});
});
};
module.exports = app;
Thanks all people that help me.
Here is the code with queries to work with a tile server.
I used this query to get an array of keys:
const sql = SELECT ARRAY_AGG(f) as keys FROM (SELECT
jsonb_object_keys(properties) f FROM ${options.layerName} group by f)
u;
And later, a function to create a query to get each property as a column called generateSQL.
I hope the code will be usefull.
/** CONSTANTS **/
const TILE_SIZE = 256;
const PROJECTION_STRING = '+init=epsg:3857';
/** LIBRARIES **/
var zlib = require('zlib');
var express = require('express');
var mapnik = require('mapnik');
var Promise = require('promise');
var SphericalMercator = require('sphericalmercator');
const { pool } = require('../postgressql/config');
var mercator = new SphericalMercator({
size: TILE_SIZE
});
mapnik.register_default_input_plugins();
var app = express();
app.get('/:namelayer/:z/:x/:y.pbf', (req, res, next) => {
var options = {
x: parseInt(req.params.x),
y: parseInt(req.params.y),
z: parseInt(req.params.z),
layerName: req.params.namelayer
};
const sql = `SELECT ARRAY_AGG(f) as keys FROM (SELECT jsonb_object_keys(properties) f FROM ${options.layerName} group by f) u`;
try {
pool.query(sql, (error, results) => {
if (error) {
return res.status(500).json({
ok: false,
message: error
});
}
const keys = (results && results.rows && results.rows.length > 0 && results.rows[0].keys && results.rows[0].keys.length >0) ? results.rows[0].keys.slice() : [];
const sql = generateSQL(options, keys);
makeVectorTile(options, sql).then( (vectorTile) => {
zlib.deflate(vectorTile, (err, data) => {
if (err) {
return res.status(500).send(err.message);
}
res.setHeader('Content-Encoding', 'deflate');
res.setHeader('Content-Type', 'application/x-protobuf');
res.setHeader('Access-Control-Allow-Origin', '*');
return res.send(data);
});
});
});
} catch (e) {
res.status(404).send({
error: e.toString(),
});
}
});
function generateSQL(options, keys) {
if (keys.length === 0) {
return `select table_id, geom from ${options.layerName}`;
} else {
let sql = "";
keys.forEach( key => {
sql = sql + `(properties->>'${key}') as ${key},`;
});
sql = `select table_id, ${sql} geom from ${options.layerName}`
return sql;
}
};
function makeVectorTile(options, sql) {
var extent = mercator.bbox(options.x, options.y, options.z, false, '3857');
var map = new mapnik.Map(TILE_SIZE, TILE_SIZE, PROJECTION_STRING);
map.extent = extent;
var layer = new mapnik.Layer(options.layerName);
layer.datasource = new mapnik.Datasource({
type: process.env.DB_TYPE,
dbname: process.env.DB_DATABASE,
// table: options.layerName,
table: `(${sql}) as tile`,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD
});
layer.styles = ['default'];
map.add_layer(layer);
return new Promise( (resolve, reject) => {
var vtile = new mapnik.VectorTile(parseInt(options.z), parseInt(options.x), parseInt(options.y));
map.render(vtile, function (err, vtile) {
if (err) {
return reject(err);
}
console.log(`${vtile.getData().length} KB`);
resolve(vtile.getData());
});
});
};
module.exports = app;

How can I execute db.copyDatabase through NodeJS's MongoDB native driver?

I do have a shell script that invokes
mongo --eval "db.copyDatabase('somedatabase', 'somedatabase_duplicate', 'sourcehost')"
to copy a database.
Currently I am stuck with doing the same from within a Node.JS application. Calling
mongoCommand = `db.copyDatabase("somedatabase", "somedatabase_duplicate", "localhost")`;
db.command(mongoCommand, function(commandErr, data) {
if(!commandErr) {
log.info(data);
} else {
log.error(commandErr.errmsg);
}
});
Always resulsts in a "no such command" error message.
Edit for clarification: Using db.admin().command() results in the same problem and using the command suggested in enter link description here, too.
What's the correct way to call this command or, alternatively, to clone a database from Node.JS?
Well, you are trying to copy database which is administration operation so have to do with admin account. Again, to copy database command is copydb.
try running this command in shell, db.copyDatabase and you'll see source of command.
try:
var assert = require('assert');
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017/test';
MongoClient.connect(url, function(err, db) {
if (err) {
console.log(err);
}
else {
var mongoCommand = { copydb: 1, fromhost: "localhost", fromdb: "test", todb: "test_dup" };
var admin = db.admin();
admin.command(mongoCommand, function(commandErr, data) {
if (!commandErr) {
console.log(data);
} else {
console.log(commandErr.errmsg);
}
db.close();
});
}
});
//core modules
const assert = require('assert')
const MongoClient = require('mongodb').MongoClient;
const moment = require('moment');
const mongo = require('mongodb')
//custom modules
let { ip, port, database } = require('./dbUpgradeConfig')
const url = `mongodb://${ip}:${port}`
let todayDate = moment().format('DD/MM/YYYY HH:mm')
console.log(todayDate)
const myDate = new Date()
console.log(myDate)
var d = Date(Date.now());
// Converting the number of millisecond in date string
a = d.toString()
// Options for mongoDB
const mongoOptions = { useNewUrlParser: true }
let db
//TODO: handle reconnect
let connect = () => {
return new Promise((resolve, reject) => {
if (db) resolve()
else {
mongo.connect(url, mongoOptions, (err, client) => {
if (err) reject(err)
else {
db = client.db(database)
resolve()
}
})
}
})
}
/**
* #description create duplicate database from current database in mongodb
*/
let CloneDb = () => {
return new Promise((resolve, reject) => {
connect()
.then(() => {
console.log(db)
let mongoCommand = { copydb: 1, fromhost: "localhost", fromdb: "db_name", todb: "db_name_duplicate" }
let adminDB = db.admin()
adminDB.command(mongoCommand, function (commandErr, data) {
if (!commandErr) {
console.log(data)
} else {
console.log(commandErr.errmsg)
}
});
})
})
}
CloneDb().then(data => {
// debugger;
console.log("The clone db", data)
})

Why this promise.all does not work?

var Promise = require("bluebird");
var MongoDB = Promise.promisifyAll(require('mongodb'));
var MongoClient = MongoDB.MongoClient;
var database = "mongodb://localhost/test";
MongoClient.connect(database)
.then(function(db) {
var c1 = db.collection('c1');
var c2 = db.collection('c2');
return Promise.all([
c1.count().then(function(count) {
if(count==0) {
return c1.insertMany([{a:1},{a:2}]);
}
else { // what should I write here?
} //
}),
c2.count().then(function(count) {
if(count==0) {
return c2.insertMany([{a:1},{a:2}]);
}
})
]);
})
.catch(function(err) {
console.log(err)
});
It just hangs there.
And what should I write in else part?
if(count==0) {
return c1.insertMany([{a:1},{a:2}]);
}
else { // what should I write here?
} //
I guess db.collection() returns a promise as well so you need to write something like this
var Promise = require("bluebird");
var MongoDB = Promise.promisifyAll(require('mongodb'));
var MongoClient = MongoDB.MongoClient;
var database = "mongodb://localhost/test";
var insertIfEmpty = function(collection) {
collection.count().then(function(count) {
if(count==0) {
return collection.insertMany([{a:1},{a:2}]);
}
else {
return Promise.resolve()
});
}
MongoClient.connect(database)
.then(function(db) {
var promisedCollections = [db.collection('c1'), db.collection('c2')]
return Promise.all(promisedCollections).map(insertIfEmpty);
})
.catch(function(err) {
console.log(err)
});
If you need to populate the collections one at a time you can use .each in place of .map

Node MongoDB memory leak issue

I'm writing a webservice using Node.js.
This webservice makes calls to a MongoDB and MSSQL.
For MSSQL i've use npm mssql library, for mongo i use the native npm mongodb library.
I use Q as my promise library.
I've a memory leak issue running a find over a MongoDB collection. I simply need to get elements from a connection. And eventually update the status of elements i get.
See my sample code below.
var Q = require('q');
var connection = require('..\connection.js'); //the connection module open a connection that can be used with pools.
function list(req, res) {
return Q.Promise(function(resolve, reject, notify) {
var collection = null;
var result = [];
var cursor = null;
Q.fcall(function(){}).then(function() {
collection = connection.collection(collectionName);
})
.then(function() {
cursor = collection.find({ fieldstatus : 0 });
return Q.Promise(function(resolve, reject, notify) {
Q.allSettled(cursor.each(function(err, item){
return Q.fcall(function(){
try {
if(item != null) {
result.push({
field1 : item.field1,
field2 : item.field2,
fieldstatus : item.fieldstatus
});
collection.update({_id: item._id}, {$set: {fieldstatus : 1}});
}
resolve(result);
} catch (err){
reject(err);
}
})
.fin(function() {
cursor.close();
});
}));
});
})
.then(function(ret) {
resolve(ret);
})
.fail(function(err) {
reject([ err.toString() ]);
})
.fin(function() {
result = null;
cursor = null;
collection = null;
});
})
.fail(function(err) {
throw([ err.toString() ]);
});
}
}
UPDATED : Answer 1
The code below seems to works without leak issuess.
var Q = require('q');
var connection = require('..\connection.js'); //the connection module open a connection that can be used with pools.
function list(req, res) {
return Q.Promise(function(resolve, reject, notify) {
var collection = null;
var result = [];
var cursor = null;
Q.fcall(function(){}).then(function() {
collection = connection.collection(collectionName);
})
.then(function() {
return Q.npost(
collection,
"find",
[
{ fieldstatus : 0 }
]
).then(function(ret){
return Q.npost(ret, "toArray").then(function(item){
return item;
});
})
.then(function(ret){
var result = [];
ret.forEach(function (item) {
result.push({
field1 : item.field1,
field2 : item.field2,
fieldstatus : item.fieldstatus
});
collection.update({_id: item._id}, {$set: {fieldstatus : 1}});
});
return result;
})
})
.then(function(ret) {
resolve(ret);
})
.fail(function(err) {
reject([ err.toString() ]);
})
.fin(function() {
collection = null;
});
})
.fail(function(err) {
throw([ err.toString() ]);
});
}
}

Resources