How to update postgres jsonb with dynamic variables in nodejs? [duplicate] - node.js

I have following setup for my project, using the pg node-postgres package:
The simple table 'tmp' looks like this:
According to jsonORG and the postgres docs the object:
{"foo" : true}
is syntactically valid JSON, and when using the pgAdmin Query-tool with:
UPDATE tmp SET data = '{"foo": false}' WHERE id = '1'
works fine, but when i try updating my table through my express route using pg:
router.put('/updateTMP', (req, res) => {
// I use dummies in this case instead of req.body.someKey for testing purposes
let dummyJSON = {"foo":true};
let dummyID = 1;
pg.query(`UPDATE tmp SET data = '${dummyJSON}' WHERE id = '${dummyID}'`, (errUpdate, responseUpdate) => {
if (!errUpdate) { // NO ERROR
res.json({success: true, message: responseUpdate});
}
else { // ERROR
console.log(dummyJSON);
console.log(errUpdate);
res.json({success: false, message: errUpdate});
}
})
})
I get the following error from the database:
error: invalid input syntax for type json
I've tried the to_json function from postgresql and the to-json package from npm in the express route - all with the same negative result.
Am i missing some fundamental understanding or is it some formating/quoting-issue?
Thanks in advance for your ideas! ;)
ps: And yes - I've read through this, and that article..

I had the same problem. Try converting your JS object to string using JSON.stringify() before passing it into the query as pg won't always do that for you automatically.
See this issue on GitHub for more info.

Related

Is DB a reserved word in Node.js

I am building some tests with mocha and chai(expect).
Keeping it simple as I am learning about testing methodology as I go along.
I have a mysql db layer in a config file.
Testing the db parameters, I ran into a weird issue.
These db parameters test fine:
host= 'localhost',
user='foo',
password='bar',
The tests:
var expect = require('chai').expect;
var db = require('../db/config.ini');
describe('Database Access', function() {
it('HOST parameter should be a string', function() {
expect(host).to.be.a('string');
});
it('USER parameter should be a string', function() {
expect(user).to.be.a('string');
});
it('PASSWORD parameter should be a string', function() {
expect(password).to.be.a('string');
});
it('DB parameter should be a string', function() {
expect(db).to.be.a('string');
});
it('HOST parameter should equal localhost', function() {
expect(host).to.equal('localhost');
});
it('USER parameter should equal foo', function() {
expect(user).to.equal('foo');
});
it('PASSWORD parameter should equal bar', function() {
expect(password).to.equal('bar');
});
it('DB parameter should equal thatone', function() {
expect(context).to.equal('thatone');
});
});
When I add the database to choose,
db='thatone';
The test fails the parameter because it reads it as an object.
1) Database Access DB parameter should be a string:
AssertionError: expected {} to be a string
at Context.<anonymous> (test/db_tests.js:21:20)
If I change the variable name to "context" the test passes as expected.
I'm wondering if there is something obvious I am missing about using "db" as a variable.
UPDATE
Really stupid, novice level mistake.
So focused on learning testing methodology I didn't realize I had created the
'db' var as a require to the 'ini' and then referenced it later as though it was unique.
Really dumb. Rushing through this recklessly to get to a destination, and failing to follow some good methodology.
The result of executing this is not a string:
var db = require('../db/config.ini');
It seems you are trying to get a file in some INI dialect to be meaningfully interpreted by Node. Node does not support this by default. If you do not get an error while loading it, the most likely reason is that the text you have in there happens to also be valid JavaScript but since INI files do not contain proper code to export something (i.e. the file does not contain exports.db = "something" or module.exports = { ... } or something similar), then the module has the value {}.
You need to add one of the multiple npm packages that will automatically interpret an INI file and provide a meaningful value. I cannot recommend one as I don't use INI files in my software but you can search npm for a package that will perform the translation for you.

How to work with NumberLong() with nodejs mongo driver

I need to insert data into my mongoDB, like such:
db.collection('Test').insert({
"Name" : "Some",
"UserID" : NumberLong(2147483647),
...
Inserts should happen from a nodejs script that interacts with mongo db
All is well, except for the NumberLong().
I'm getting the following error:
ReferenceError: NumberLong is not defined
at /root/MongoPolluter/MongoPolluter.js:107:23
at connectCallback (/root/MongoPolluter/node_modules/mongodb/lib/mongo_client.js:505:5)
at /root/MongoPolluter/node_modules/mongodb/lib/mongo_client.js:443:13
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickCallback (internal/process/next_tick.js:104:9)
What I have tried:
adding var BSON = require('bson'); after installing it. Maybe I should use BSONElements?
Read this: MongoDB differences between NumberLong and simple Integer? - from which I go the notion that I could use the NumberLong only from mongo shell? Not sure if that is correct.
Also read about this: var Long = require('mongodb').Long; - should I just replace NumbreLong() w/ Long.fromString('')? Is there no way of getting the NumberLong() to work?
Thanks
NumberLong is using for mongo shell only. If you use in nodejs (javascript) it no mean.
I use mongoose and only Number type of data
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var MyNumber = mongoose.model('my_number', { long_number: Number });
var record = new MyNumber({ long_number: 1234556 });
record.save(function (err) {
if (err) {
console.log(err);
} else {
console.log('ok');
}
});
// have to defind ObjectId when use even it a default type data of mongodb
var id = mongoose.Types.ObjectId('4edd40c86762e0fb12000003');

Knex migration not working when using migration API

I am new to knex migrations and for the past 2 days I have been struggling to get it working but nothing happen. I am trying to run my migrations programmatically using the knex.migration object.
First using the cli, I create a migration file in the migrations directory. Here is its content:
exports.up = function(knex, Promise) {
return Promise.all([
knex.schema.createTable('users', function (table) {
table.increments('id').primary();
table.string('username');
table.string('password');
table.string('email');
table.string('name');
table.timestamp('date');
}),
]);
};
exports.down = function(knex, Promise) {
};
Then from my code I initialize the Knex object:
var knex = Knex({
client:'sqlite3',
connection:{
filename: './knex.sqlite'
}
});
Then I execute the migration:
knex.migrate.latest().then(()=>{
// console.log()
}).catch(err =>{
//
});
But absolutely nothing happens. My migration file is never executed and there is no error or warning message. So I don't know where to look at to start searching for the problem. When I look at my sqlite database, I can see that tables knex_migrations, knex_migrations_lock and sqlite_sequence have been created.
So what I am doing wrong here? Is there something I am missing?
Thanks for any suggestion
There's no requirement to use the CLI tools. Sometimes it's not possible to use it due to its limitations and in this case it's indeed possible to use the migration API directly, like so:
const knex = require('knex')({
// Here goes the Knex config
});
const migrationConfig = {
directory: __dirname + './migrations',
}
console.info('Running migrations in: ' + migrationConfig.directory);
knex.migrate.latest(migrationConfig).then(([batchNo, log]) => {
if (!log.length) {
console.info('Database is already up to date');
} else {
console.info('Ran migrations: ' + log.join(', '));
}
// Important to destroy the database, otherwise Node script won't exit
// because Knex keeps open handles.
knex.destroy();
});
There was two issues in the original question:
The migration directory was not specified - in this case Knex is not smart and will simply not do anything instead of throwing an error. Most likely the default used by Knex is not right so it's best to specify it.
knex.destroy() was missing. In this case, the script will never exit because Knex keeps open handles on the database, so it just looks like it's stuck doing nothing.
The above script also outputs more log info to see what's exactly happening.
Knex migrations are supposed to run by Knex CLI,FYI: https://knexjs.org/#Migrations
As your code described, I found a strange issue:
knex.migrate is actually undefined, it's not a property of knex.

nodeschool:learnyoumongo "FIND" lesson fails before I write anything - config?

Currently the only thing I have in my file is the following:
var mongo = require('mongodb').MongoClient,
url = 'mongodb://localhost:27017/learnyoumongo';
console.log(mongo);
When I run the verify command, I get the following error:
/usr/local/lib/node_modules/learnyoumongo/exercises/find/exercise.js:37
db.collection('parrots').remove({}, function(err) {
^
TypeError: Cannot read property 'collection' of undefined
at Exercise.<anonymous> (/usr/local/lib/node_modules/learnyoumongo/exercises/find/exercise.js:37:5)
at next (/usr/local/lib/node_modules/learnyoumongo/node_modules/workshopper-exercise/exercise.js:260:17)
at Exercise.end (/usr/local/lib/node_modules/learnyoumongo/node_modules/workshopper-exercise/exercise.js:266:5)
at Workshopper.end (/usr/local/lib/node_modules/learnyoumongo/node_modules/workshopper/workshopper.js:191:12)
at Workshopper.done (/usr/local/lib/node_modules/learnyoumongo/node_modules/workshopper/workshopper.js:323:19)
at Exercise.<anonymous> (/usr/local/lib/node_modules/learnyoumongo/node_modules/workshopper-exercise/exercise.js:149:14)
at /usr/local/lib/node_modules/learnyoumongo/node_modules/workshopper-exercise/exercise.js:136:16
at Exercise.<anonymous> (/usr/local/lib/node_modules/learnyoumongo/node_modules/workshopper-exercise/filecheck.js:10:14)
at FSReqWrap.oncomplete (fs.js:95:15)
When I took a look at the exercises.js file, I see the error is pointing to the .addCleanup function and the db it is trying to close is undefined.
This seems like a connection/configuration error, but I passed the first two modules. Can anyone help?
Update
This is definitely a connection error. The previous scenario was created using the command in the workshop module mongod --port 27017 --dbpath=./data, however when I opened a new terminal tab and just ran mongo without any arguments, the verify command actually output the "Actual/Expected" evaluation and module results.
To the user who asked for the rest of the script, please understand if you are unfamiliar with nodeschool that this is an entire repository with module based automated/interactive tutorials, so this is not all of the code. In any case, here is what you requested:
var mongo = require('mongodb').MongoClient
, exercise = require('workshopper-exercise')()
, filecheck = require('workshopper-exercise/filecheck')
, execute = require('workshopper-exercise/execute')
, comparestdout = require('workshopper-exercise/comparestdout')
exercise = filecheck(exercise)
exercise = execute(exercise)
exercise = comparestdout(exercise)
var db, url = 'mongodb://localhost:27017/learnyoumongo'
exercise.addSetup(function(mode, cb) {
var self = this
this.submissionArgs = [3]
this.solutionArgs = [3]
mongo.connect(url, function(err, _db) {
if (err) return cb(err)
db = _db
col = db.collection('parrots')
col.insert([{
name: 'Fred'
, age: 1
}, {
name: 'Jane'
, age: 3
}, {
name: 'Jenny'
, age: 10
}], cb)
})
})
exercise.addCleanup(function(mode, pass, cb) {
db.collection('parrots').remove({}, function(err) {
if (err) return cb(err)
db.close()
cb()
})
})
module.exports = exercise
I think that should be:
var mongo = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/learnyoumongo', function(err, db) {
console.log(err);
});
There was definitely a connection problem. I'm not sure exactly where the bug was, but I reloaded learnyoumongo and reinstalled a couple of node packages. When I did that I had to go back and change permissions on the data directory again.
My recommendation if anyone else faces strange config errors, is to try to reinstall. Then when you connect, it doesn't hurt to re-verify the CONNECT module to make sure you have a good connection when you start your work space.

How to access multiple models from a controller

I have a Locations model and a Recorders model. I want to be able to pass all of the data for both data sets to my view model. How can I access them though because I think they're not in scope since I'm getting undefined errors because I'm calling 'all'
https://gist.github.com/3998302
var Main = function () {
this.index = function (req, resp, params) {
var self = this;
var data = {};
geddy.model.Locations.all(function(err, locations) {
data.locations = locations;
geddy.model.Recorders.all(function(err, recorders) {
data.recorders = recorders;
self.respond({params: params, data: data}, {
format: 'html'
, template: 'app/views/locations/index'
}
});
}););
};
};
exports.Main = Main;
Error snippet:
timers.js:103
if (!process.listeners('uncaughtException').length) throw e;
^
TypeError: Cannot call method 'all' of undefined
at index (G:\code\PeopleTracker\app\controllers\main.js:23:24)
at controller.BaseController._handleAction.callback (C:\Users\Chris\AppData\Roaming\npm\node_modules\geddy\lib\base_
controller.js:387:22)
So it looks like you're initializing the data variable to 'undefined'. Try data = {} instead. If that doesn't fix it, I'll do some troubleshooting with you.
EDIT
If that doesn't do it for you, try installing geddy again:
npm uninstall -g geddy && npm install -g geddy
If that doesn't do it, make sure that your DB is actually running, make sure that the models are defined (try geddy console to check your models), and make sure that you're on the latest stable version of node.
Very late to the party, but I believe you can just call
geddy.model.Locations.all(function(err, locations) {
geddy.model.Recorders.all(function(err, recorders) {
var data = {};
data.locations = locations;
data.recorders = recorders;
self.respond({params: params, data: data}, {
format: 'html'
, template: 'app/views/locations/index'
}
});
}););
You could also have the respond say
self.respond({params: params, locations: locations, recorders: recorders});
but if you want all of that data available from the data literal you need it defined in the lowest scope callback. The callbacks can read above their scope but they cannot write above it.

Resources