Can't set keys in Redis in Node.js - node.js

I am trying to use Redis in Node.js. I am doing something wrong... I can't get my head around it.
var redis = require("redis"), client = redis.createClient();
client.on("error", function (err) {
console.log("error event - " + client.host + ":" + client.port + " - " + err);
});
/* first attempt */
console.log('first attempt');
var before = client.get("test");
console.log(before);
if(client.exists("test")) {
console.log("The value exists");
} else {
console.log("The value doesn't exists");
client.set("test","koen");
}
var after = client.get("test");
console.log(after);
/* second attempt */
console.log('--------------');
console.log('second attempt');
var before = client.get("test");
console.log(before);
if(client.exists("test")) {
console.log("The value exists");
} else {
console.log("The value doesn't exists");
client.set("test","koen");
}
var after = client.get("test");
console.log(after);
I am unable to set any keys... The following is displayed in the console:
first attempt
false
The value doesn't exists
false
--------------
second attempt
false
The value doesn't exists
false

client.set() is not synchronous. You need to supply a callback as the last argument, at which point your key will have been set.

Here is an example how to set and get "test":
client.set("test", "koen", function (err, res) {
console.log("set: ", res)
client.get("test", function (err, res) {
console.log("get: ", res);
});
});
Remember that all your calls must be asynchronous.

Related

Nodejs/Async: How does callback work in iteratee function for async.map as mentioned in code snippet

Being new to nodejs ans async following is the code that I came across.
app = express();
/*
other express use calls like - app.use(bodyParser.json());
*/
var async = require("async");
var server;
app.post('/callType/call', function(req, res) {
var startTime = Date.now();
server = req.body.server;
//async.map asynchronuously call enrollStep1 for every element in the req.body.nodes array
//HOW DOES THIS WORK??!! - WHERE IS THE CALLBACK DEFINED OR SOURCED FROM???
//******************************************************
async.map(req.body.nodes, function(node, callback) {
someFunc(node.property1,node.property2,callback)
},
//This function is called when every task triggered by async.map has called its callback.
function(err, results) {
var response = {};
if (err) {
response.success = false;
response.error = err;
console.log("ERROR returned: " + JSON.stringify(response));
res.json(response);
} else {
var returnResults = [];
//Results is an array of array - flatten it
var flattenedResults = [].concat.apply([], results);
//then remove duplicates
for (var i = 0; i < flattenedResults.length; i++){
var obj = flattenedResults[i];
var isDup = returnResults.some(function(element) {
return element.tid === obj.tid;
});
if (!isDup) {
returnResults.push(obj);
}
}
response.success = true;
response.results = returnResults;
res.json(response);
}
});
});
function someFunc(property1, property2, callback) {
var url = '/'+callTypes +'/'+ call +'/'+ property1 +'/'+ property2
urClient
.get(server + url)
.header('Content-Type', 'application/json')
.end(
function(response) {
if (response.code !== 200) {
callback("Error " + ". Code: " + response.code + " Response: " + JSON.stringify(response));
} else {
callback("Success " + ". Code: " + response.code + " Response: " + JSON.stringify(response));
}
}
);
}
The iteratee function for async.map has a definition starting function(node, callback) { but the callback function is never assigned. How does the callback work over here.
Isn't it supposed to be assigned somewhere like callback = myCallbackFunction;
The async.map takes 3 arguments, the array/object, the function to map the data and the callback function, so your code should be:
async.map(req.body.nodes, someFunc , function(err, results) {
if (err) return console.log(err);
console.log(results);
});
And your someFunc should be:
function someFunc(item, callback) {
// do something with item
// it's each item in the original array/object
callback('The results');
}
This is a basic example: http://code.runnable.com/UyR-6c2DZZ4SmfSh/async-map-example-for-node-js

Getting Response of a function defined in another file in node.js

I have a socket function defined as
var funcs = require('./funcs');
socket.on(EVENT_ACCEPT_ORDER, function(data, callback)
{
data = JSON.parse(data);
var bookingId = data.bookingId;
var userId = data.userId;
console.log("Accepting booking...." + bookingId);
var query = "UPDATE bookings SET bookingStatus = " + BOOKING_STATUS_ACCEPTED + " WHERE id = " + bookingId + " AND bookingStatus = " + BOOKING_STATUS_IN_QUEUE;
con.query(query, function(err, rows,fields)
{
if(err)
{
console.log("mysql query error");
}
else
{
if(rows.changedRows > 0)
{
var indexOfUser = usersList.indexOf(userId);
if(indexOfUser > -1)
{
userSockets[indexOfUser].emit(EVENT_USER_ORDER_ACCEPTED);
}
callback({"message": "Success","error":false, "booking": funcs.getBooking(con, bookingId)});
}
else
callback({"message": "Success","error":true});
}
});
});
Funcs is defined as
module.exports = {
"getBooking": function (con, bookingId)
{
var query = "SELECT * FROM bookings WHERE id = " + bookingId + " LIMIT 1";
con.query(query, function(err, rows,fields)
{
if(err)
{
console.log("mysql query error");
}
else if (rows.length == 1)
{
var booking = rows[0];
var userId = rows[0]['userId'];
var query = "SELECT id, name, phone, imagePath FROM users WHERE id = " + userId + " LIMIT 1";
con.query(query, function(err, rows,fields)
{
if(err)
{
console.log("mysql query error");
}
else if (rows.length == 1)
{
booking['user'] = rows[0];
return booking;
}
});
}
});
}
}
Everything is running fine except
callback({"message": "Success","error":false, "booking": funcs.getBooking(con, bookingId)});
in this function instead of booking, i am only getting
{"error":false,"message":"Success"}
Why am i not getting the booking function result?
You are not getting the result, because the result of the callback function in con.query is not returned to the caller of getBooking. It is the asynchronous pattern, which you are not processing correctly.
The way it is supposed to work is that the getBooking gets an extra argument: a function to be called when data are available (in an internal asynchronous call to con.query). Such a function is then provided by the caller and in this function you do whatever you want with the data:
funcs.js
"getBooking": function (con, bookingId, callback) {
...
con.query(query, function(err, rows,fields) {
...
// instead of return booking do
callback(err, booking);
...
}
}
main module
// instead of
callback({"message": "Success","error":false, "booking": funcs.getBooking(con, bookingId)});
// do
funcs.getBooking(con, bookingId, function(err, booking) {
callback({"message": "Success","error":false, "booking": booking});
});
I am afraid this is not the only issue in your code, but this should be the first to fix. Read further about processing asynchronous calls in general and specifically in node.js and fix other places in your code correspondingly.

How to return the callback in a variable in node.js with npm synchronize

I'm using nodejs and I want to avoid multiple nested callbacks. How can I use synchonize to do that ?
More precisely how can I return the pubkeysObj from the callback of the request in a variable and use it in the rest of the script ?
var sync = require('synchronize');
var fiber = sync.fiber;
var await = sync.await;
var defer = sync.defer;
try {
fiber(function() {
console.log('before findKeyPair');
var pubkeysObj2 = await( findKeyPair( defer() ) );
console.log('after findKeyPair pubkeysObj2: ' + pubkeysObj2);
console.log('before makeKeyPairs');
var pubkeyArray2 = await( makeKeyPairs( pubkeysObj2, defer() ) );
console.log('after makeKeyPairs pubkeyArray2: ' + pubkeyArray2);
});
} catch(err) {
console.log('err: ' + err);
}
function findKeyPair(){
Keypair.find({}, {pubkey: 1, _id: 0}, function(err, pubkeysObj) { //mongoose db
if (err) res.redirect('/');
console.log('inside findKeyPair pubkeysObj: ' + pubkeysObj);
return pubkeysObj; // ?????????
});
}
function makeKeyPairs(pubkeysObj3){
console.log('inside makeKeyPairs: pubkeysObj3:' + pubkeysObj3);
var pubkeyArray = [];
pubkeyArray = Object.keys(pubkeysObj3).map(function(_) { return pubkeysObj3[_].pubkey; })
return pubkeyArray; // ????
}
The output is:
before findKeyPair
inside findKeyPair pubkeysObj: { pubkey: 'n2eTmd37KTGhRZNJsf9tfVdCG1YejciETu' },{ pubkey: 'n2cBvz74bMGUf35gAdnSksbBnW1m4HfCmg' }
Would you be open to using wait.for?
I rewrote my code using "wait.for" and now I can receive the object KeypairObj from the database and pass it to the next function makeKeyPairs.
Inside this function I can print my array (pubkeyArray) but
I can't get the returned value (pubkeyArray2) and the last line of the function findKeyPair is not executed.
here is the new code:
var wait = require('wait.for');
var Keypair = require('./app/models/Keypair');
try {
// launch a new fiber
wait.launchFiber(findKeyPair, Keypair);
}
catch(err) {
console.log('err' + err);
}
function findKeyPair(Keypair){
var KeypairObj = wait.forMethod(Keypair,'find', {}, {pubkey: 1, _id: 0});
console.log('1: ' + KeypairObj.toString());
var pubkeyArray2 = wait.for(makeKeyPairs, KeypairObj);
console.log('3: pubkeyArray2: ' + pubkeyArray2); // not executed !!!
}
function makeKeyPairs(pubkeysObj3){
pubkeyArray = Object.keys(pubkeysObj3).map(function(_) { return pubkeysObj3[_].pubkey; });
console.log('2: pubkeyArray: ' + pubkeyArray);
}
and the output:
1: { pubkey: 'n2eTmd37KTGhRZNJsf9tfVdCG1YejciETu' },{ pubkey: 'n2cBvz74bMGUf35gAdnSksbBnW1m4HfCmg' }
2: pubkeyArray: n2eTmd37KTGhRZNJsf9tfVdCG1YejciETu,n2cBvz74bMGUf35gAdnSksbBnW1m4HfCmg

NODE.JS function callback to render page

I have a function getthem() that checks a mongo db for listings and returns name,streamurl for it.
I pass those as var stream to the renderme that renders the /dashboard page.
My problem is that i get the console.log("END OF FIND:"+JSON.stringify(stream))
to show my test input, but nothing goes to the render.
im using ejs to render. How can i get the result passed to the page ?
router.get('/dashboard', function (req, res) {
var foo = getthem();
function getthem() {
var group = "tesint";
console.log('geting for group : ' + group);
var mdlListings = require('../models/listings.js');
var myresult = "tet";
mdlListings.find({}, "name streamurl", function (err, data) {
if (err) {
console.error(err);
return;
}
if (data === null) {
console.log("No results");
return;
}
var stream = { };
data.forEach(function (streams) {
console.log("Got " + streams.name + " " + streams.streamurl);
stream[streams.name] = streams.streamurl;
// stream += 'name: '+streams.name+'},{streamurl: '+streams.streamurl;
// console.log("stram arry "+stream[streams.name] )
console.log("END OF FIND:"+JSON.stringify(stream))
}, renderme(stream));
// console.log("Result:", votes);
//var myresult = Object.keys(stream).map(function (name) {
// return { name: name, url: stream[name] };
//})
console.log("before return stream "+stream);
return stream;
});
}
function renderme(resa) {
console.log("RESA"+JSON.stringify(resa))
var resa = JSON.stringify(resa);
res.render('dashboard', {
title: 'Dashboard',
user: req.user,
listing: resa
}
)
}
You're passing the result of renderme(stream) as a second argument to forEach(). renderme(stream) is then evaluated immediately before your forEach() callback is called, when stream is still an empty object. My guess is you want something like this:
data.forEach(function (streams) {
console.log("Got " + streams.name + " " + streams.streamurl);
stream[streams.name] = streams.streamurl;
console.log("END OF FIND:"+JSON.stringify(stream))
});
renderme(stream);
Actually i figure that why would i pass the function as i could just do whatever i need to directly in there.
That worked perfectly, thanks for the tip.
data.forEach(function (streams) {
console.log("Got " + streams.name + " " + streams.streamurl);
stream[streams.name] = streams.streamurl;
});
res.render('dashboard', {
title: 'Dashboard',
user: req.user,
listing: data
}
)

Why during $save() it generates a new entry in the mongoDB with a string _id?

MEAN stack newbie here. Probably asking a silly question.
As an exercise, I have been trying to implement a prototype SPA which shows a series of task cards on the screen (kinda like Trello).
For now, each card has 4 fields:
_id: ObjectId
content: String
workflow: String
state: String
I am using MongoDB for the database (entered some test data using Robomongo), I have node.js installed on my machine, as well as Express.js.
My server.js file looks like the following:
var express = require('express'),
cards = require('./routes/cards');
var app = express();
app.configure(function() {
app.use(express.logger('dev'));
app.use(express.bodyParser());
});
app.get('/cards', cards.findAll);
app.get('/cards/:id', cards.findById);
app.post('/cards', cards.addCard);
app.put('/cards/:id', cards.updateCard);
app.listen(3000);
console.log('Listening on port 3000...');
My routes/cards.js on the server side look like the following:
var mongo = require('mongodb');
var Server = mongo.Server,
Db = mongo.Db,
BSON = mongo.BSONPure;
var server = new Server('localhost', 27017, {auto_reconnect: true});
var db = new Db('mindr', server);
db.open(function(err, db) {
if(!err) {
console.log("Connected to 'mindr' database");
db.collection('cards', {strict:true}, function(err, collection) {
if (err) {
console.log("The 'cards' collection doesn't exist.");
}
});
}
});
exports.findById = function(req, res) {
var id = req.params.id;
console.log('Retrieving card: ' + id);
db.collection('cards', function(err, collection) {
collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item) {
res.send(item);
});
});
};
exports.findAll = function(req, res) {
db.collection('cards', function(err, collection) {
collection.find().toArray(function(err, items) {
res.send(items);
});
});
};
exports.addCard = function(req, res) {
var newCard = req.body;
console.log('Adding card: ' + JSON.stringify(newCard));
db.collection('cards', function(err, collection) {
collection.insert(newCard, {safe:true}, function(err, result) {
if (err) {
res.send({'error':'An error has occurred'});
} else {
console.log('Success: ' + JSON.stringify(result[0]));
res.send(result[0]);
}
});
});
}
exports.updateCard = function(req, res) {
var id = req.params.id;
var card = req.body;
console.log('Updating card: ' + id);
console.log(JSON.stringify(card));
db.collection('cards', function(err, collection) {
collection.update({'_id':new BSON.ObjectID(id)}, card, {safe:true}, function(err, result) {
if (err) {
console.log('Error updating card: ' + err);
res.send({'error':'An error has occurred'});
} else {
console.log('' + result + ' document(s) updated');
res.send(card);
}
});
});
}
exports.deleteCard = function(req, res) {
var id = req.params.id;
console.log('Deleting card: ' + id);
db.collection('cards', function(err, collection) {
collection.remove({'_id':new BSON.ObjectID(id)}, {safe:true}, function(err, result) {
if (err) {
res.send({'error':'An error has occurred - ' + err});
} else {
console.log('' + result + ' document(s) deleted');
res.send(req.body);
}
});
});
}
When I get the cards from the DB in my AngularJS controller, everything goes fine. All the cards are correctly displayed on the screen. This is the code that gets the cards:
var mindrApp = angular.module('mindrApp', ['ngResource'])
mindrApp.controller('WorkflowController', function ($scope, $resource) {
var CardService = $resource("http://localhost:3000/cards/:cardId", {cardId:"#id"});
$scope.cards = CardService.query();
});
On each card there are some buttons that can be used to change the state of the card to the next state available in the workflow (as defined by the current state available actions).
When the button is clicked, the card id and the next state are passed to a function in the controller:
<div class="btn-group btn-group-xs">
<button type="button" class="btn btn-default"
ng-repeat="currentAction in currentState.actions | filter:{default:true}"
ng-click="processCard(currentCard._id, currentAction.next)">
{{currentAction.name}}
</button>
</div>
And this is the processCard function in the controller:
$scope.processCard = function(id, nextState) {
var currentCard = CardService.get({cardId: id}, function(){
currentCard.state = nextState;
currentCard.$save();
});
};
What's happening is that when I click the button, instead of changing the state of the current card, a new card is created with an id field of type String. This is the output of the server:
Retrieving card: 52910f2a26f1db6a13915d9f
GET /cards/52910f2a26f1db6a13915d9f 200 1ms - 152b
Adding card: {"_id":"52910f2a26f1db6a13915d9f","content":"this is some content for this really cool card","workflow":"simple","state":"completed"}
Success: {"_id":"52910f2a26f1db6a13915d9f","content":"this is some content for this really cool card","workflow":"simple","state":"completed"}
POST /cards 200 1ms - 150b
Any idea why this is happening? Why is it calling the addCard function on the server instead of calling the updateCard function?
The $save() action of a $resource object use POST as default request type (Read more here). So in your case, a POST request to the route /cards/:id was called, so as a result, a new card was created.
Either create a new route entry to handle POST update request in server.js
app.post('/cards/:id', cards.updateCard);
Or add another action that use PUT to your CardService and call it when you want to update your card
var CardService = $resource("http://localhost:3000/cards/:cardId", {cardId:"#id"},
{ update: { method: 'PUT' } }
);
// update the card
...
currentCard.$update();
Ok, so I figured it out. The two problems I were having were:
1) instead of updating the existing item in the database, it was creating a new one with the same ID but in string format instead of using the ObjectId format.
2) any time I called $update, it would not append the ID to the path, but always PUT to /cards.
So here are the solutions to each of the problems.
1) This is really a hack that assumes that ALL id are in ObjectId format. I don't like this solution but for now it works and I am sticking to it. All I had to do was to add the line that converts the card._id back to ObjectId format to the updateCard function inside the cards.js file on the server side.
exports.updateCard = function(req, res) {
var id = req.params.id;
var card = req.body;
console.log('Updating card: ' + id);
console.log(JSON.stringify(card));
card._id = new BSON.ObjectID.createFromHexString(card._id); // HACK!
db.collection('cards', function(err, collection) {
collection.update({'_id':new BSON.ObjectID(id)}, card, {safe:true}, function(err, result) {
if (err) {
console.log('Error updating card: ' + err);
res.send({'error':'An error has occurred'});
} else {
console.log('' + result + ' document(s) updated');
res.send(card);
}
});
});
}
2) This was a two part fix. First, I had to modify the services.js file to explicitly say that I want to use update via PUT:
var mindrServices = angular.module('mindrServices', ['ngResource']);
mindrServices.factory("Card", ["$resource",
function($resource) {
return $resource("http://localhost:3000/cards/:cardId", {cardId:"#id"},
{
query: {method: "GET", isArray:true},
update: {method: "PUT"}
}
);
}]);
Next, I was under the assumption that simply calling currentCard.$update() would grab the ID from the calling instance, instead I have to explicitly pass in the ID as follows:
var mindrControllers = angular.module('mindrControllers', []);
mindrControllers.controller('CardsController', ["$scope", "Card",
function ($scope, Card) {
$scope.cards = Card.query();
console.log("cards populated correctly...");
$scope.processCard = function(currentCard, currentAction) {
console.log("processCard: card[" + currentCard._id + "] needs to be moved to [" + currentAction.next + "] state... ");
currentCard.state = currentAction.next;
currentCard.$update({cardId: currentCard._id}); // passing the ID explicitly
}
This is the output I get on the server side:
Updating card: 52910eb526f1db6a13915d9c
{"_id":"52910eb526f1db6a13915d9c","content":"this is some content for this really cool card","workflow":"simple","state":"backlog"}
1 document(s) updated
PUT /cards/52910eb526f1db6a13915d9c 200 4ms - 111b

Resources