search a string in another file and replace it with another string in node js - regex

I have searched enough for this matter and found most of the answers for java same problem but for me the problem arise in a node js program.
I want to search for,
.made-easy-theme{
color:black;
}
in a css file and replace its 'black' with another color which I recieve from the client side of the program. Here is what I have tried, I have tried 3 ways, but none of them are working.
First concept I have tried is,
var main = 'temp/' + userId + '/templates/' + appId + '/css/main.css';
var color = req.body.color;
function replaceThemecolor(color) {
fs.readFile(main, 'utf-8',
function (err, data) {
if (err) {
return console.log(err)
}
else {
var str = '.made-easy-theme{color:black;}';
if (str.search("black") != -1) {
var result = data.replace(/black/g, themecolor.color);
fs.writeFile(mainCss, result, 'utf-8', function (err) {
if (err) return console.log(err);
});
}
console.log(result);
}
});
}
});
The second concept I have tried is,
fs.readFile(main, 'utf-8',
function (err, data) {
if (err) {
return console.log(err)
}
else {
var ex = '.made-easy-theme{color:black;}'.includes('black');
if (ex == true) {
var result = data.replace(/black/g, color);
fs.writeFile(main, result, 'utf-8', function (err) {
if (err) return console.log(err);
});
console.log(result);
}
}
The third concept I have tried is,
else if (data.indexOf('.made-easy-theme{color:black;}') > 0) {
console.log(data);
var result = data.replace('black', themecolor.color);
fs.writeFile(mainCss, result, 'utf-8', function (err) {
if (err) return console.log(err);
});
};
Noone of these are working for me, please help to resolve this problem

I have found the answer
function replaceThemecolor(color) {
fs.readFile(main, 'utf-8',
function (err, data) {
var searchStr = ".made-easy-theme{color:black}";
var result = searchStr.replace(new RegExp('black', ''), color);
fs.writeFile(main, result, 'utf-8', function (err) {
if (err) return console.log(err);
});
});
}
but the problem is that it clears the full content of the css file and replace only the
.made-easy-theme{
color:black;
}
the other content which was in the css file is erased. I want to keep them and replce what I want to replace

Here is a way to do it, although not the best way. This code is coupled, makes bad use of string concatenation, doesn't do enough error checking and should probably use a file stream. But it will give you an idea.
Plus, it's just a dangerous thing to do.
var fs = require('fs');
var infile = 'test.css';
var outfile = 'temp.css';
var flag = false;
var color = 'green';
var out = '';
fs.open(infile, 'r', function(err, fd){
changeLine(fd);
});
function changeLine(fd){
var buf = new Buffer(1024);
buf.fill(0);
fs.read(fd, buf, 0, 1024, null, function(err, bytesRead, buffer){
if(bytesRead === 0){
writeCSS(out);
return;
}
var str = buffer.toString('utf8', 0, bytesRead);
if(/made-easy-theme/.exec(str)){
flag = true;
}
if (/color:/.exec(str) && flag){
str = str.replace('black', color);
flag = false;
}
out += str;
changeLine(fd);
});
}
function writeCSS(str){
fs.writeFile(outfile, str, function(err, written, buffer){
fs.rename(outfile, infile);
});
}

Related

Recall dynamodb table with Alexa

Im trying to create a skill that will scan or query my dynamodb table which includes a date column, filmanme, and time.
Here is the code i have so far.
console.log('Loading function');
var AWSregion = 'us-east-1'; // us-east-1
var AWS = require('aws-sdk');
var dclient = new AWS.DynamoDB.DocumentClient();
var getItems = (event, context, callback)=>{
dclient.get(event.params,(error,data)=>{
if(error){
callback(null,"error occurerd");
}
else{
callback(null,data);
}
});
};
exports.handler = getItems;
exports.handler = (event, context, callback) => {
try {
var request = event.request;
if (request.type === "LaunchRequest") {
context.succeed(buildResponse({
speechText: "Welcome to H.S.S.M.I skill, what would you like to find",
repromptText: "I repeat, Welcome to my skill, what would you like to find",
endSession: false
}));
}
else if (request.type === "IntentRequest") {
let options = {};
if (request.intent.name === "cinema") {
if (request.intent.slots.cimema !== undefined)
var sign = request.intent.slots.cinema.value;
//Check sign is valid
if (sign === undefined || sign === null) {
options.speechText = " sorry, i didn't understant your question. can you say that again?";
options.endSession = false;
context.succeed(buildResponse(options));
return;
}
if (request.intent.slots.zodiac !== undefined && !ValidateZodiacSign(sign)) {
options.speechText = ` The Zoadiac sign ${sign} is not a valid one. Please tell a valid zodiac sign .`;
options.endSession = false;
context.succeed(buildResponse(options));
return;
}
cinema(sign, function (cinema, error) {
if (error) {
context.fail(error);
options.speechText = "There has been a problem with the request.";
options.endSession = true;
context.succeed(buildResponse(options));
} else {
options.speechText = todaysFortune;
options.speechText += " . Have a nice day ahead . ";
options.sign = sign;
options.cardText = todaysFortune;
options.endSession = true;
context.succeed(buildResponse(options));
}
});
} else if (request.intent.name === "AMAZON.StopIntent" || request.intent.name === "AMAZON.CancelIntent") {
options.speechText = "ok, good bye.";
options.endSession = true;
context.succeed(buildResponse(options));
}
else if (request.intent.name === "AMAZON.HelpIntent") {
options.speechText = "My skill will read your table depending on what is asked. For example, you can ask what about a specific date. Please refer to skill description for all possible utterences.";
options.repromptText = "What is the data sign you want to know about today? If you want to exit from my skill please say stop or cancel."
options.endSession = false;
context.succeed(buildResponse(options));
}
else {
context.fail("Unknown Intent")
}
}
else if (request.type === "SessionEndedRequest") {
options.endSession = true;
context.succeed();
}
else {
context.fail("Unknown Intent type");
}
} catch (e) {
}
};
function buildResponse(options) {
var response = {
version: "1.0",
response: {
outputSpeech: {
"type": "SSML",
"ssml": `<speak><prosody rate="slow">${options.speechText}</prosody></speak>`
},
shouldEndSession: options.endSession
}
};
if (options.repromptText) {
response.response.reprompt = {
outputSpeech: {
"type": "SSML",
"ssml": `<speak><prosody rate="slow">${options.repromptText}</prosody></speak>`
}
};
}
return response;
}
function readDynamoItem(params, callback) {
var AWS = require('aws-sdk');
AWS.config.update({region: AWSregion});
var dynamodb = new AWS.DynamoDB();
console.log('reading item from DynamoDB table');
dynamodb.scan(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else{
console.log(data); // successful response
callback(JSON.stringify(data));
}
});
var docClient = new AWS.DynamoDB.DocumentClient();
//Get item by key
docClient.get(params, (err, data) => {
if (err) {
console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("GetItem succeeded:", JSON.stringify(data, null, 2));
callback(data.Item.message); // this particular row has an attribute called message
}
});
}
///////////////////////////////////////////////////////////////////////////////
and here is my DBHandlder
const AWS = require('aws-sdk');
AWS.config.update({
region: "'us-east-1'"
});
var docClient = new AWS.DynamoDB.DocumentClient();
var table = "Cinema";
var getItems = (Id,callback) => {
var params = {
TableName: "cinema",
Key: {
"Id": Id
}
};
docClient.get(params, function (err, data) {
callback(err, data);
});
};
module.exports = {
getItems
};
i'm very new to this and i cant find muchsupport online for the skill i want to produce or anything similar.
I created a lambda function which works and will find the corresponding movie when i configure the test function to find a specified date, however this does not work with alexa
any input is helpful.

Transfer data from SQS to Dynamodb

Is there a way to transfer the messages I get from SQS and send them over to Dynamodb? I've tried making a Lambda function using CloudWatch to trigger it every minute. I'm open to using any other services in AWS to complete this task. I'm sure there's a simple explanation to this that I'm just overlooking.
*Edit my code does not work, I'm looking for either a fix to my code or another solution to accomplish this.
**Edit got it working.
'use strict';
const AWS = require('aws-sdk');
const SQS = new AWS.SQS({ apiVersion: '2012-11-05' });
const Lambda = new AWS.Lambda({ apiVersion: '2015-03-31' });
const QUEUE_URL = 'SQS_URL';
const PROCESS_MESSAGE = 'process-message';
const DYNAMO_TABLE = 'TABLE_NAME';
function poll(functionName, callback) {
const params = {
QueueUrl: QUEUE_URL,
MaxNumberOfMessages: 10,
VisibilityTimeout: 10
};
// batch request messages
SQS.receiveMessage(params, function(err, data) {
if (err) {
return callback(err);
}
// parse each message
data.Messages.forEach(parseSQSMessage);
})
.promise()
.then(function(){
return Lambda.invokeAsync({})
.promise()
.then(function(data){
console.log('Recursion');
})
}
)
.then(function(){context.succeed()}).catch(function(err){context.fail(err, err.stack)});
}
// send each event in message to dynamoDB.
// remove message from queue
function parseSQSMessage(msg, index, array) {
// delete SQS message
var params = {
QueueUrl: QUEUE_URL,
ReceiptHandle: msg.ReceiptHandle
};
SQS.deleteMessage(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
}
// store atomic event JSON directly to dynamoDB
function storeEvent(event) {
var params = {
TableName : DYNAMO_TABLE,
Item: event
};
var docClient = new AWS.DynamoDB.DocumentClient();
docClient.put(params, function(err, data) {
if (err) console.log(err);
else console.log(data);
});
}
exports.handler = (event, context, callback) => {
try {
// invoked by schedule
poll(context.functionName, callback);
} catch (err) {
callback(err);
}
};
var aws = require( "aws-sdk" );
// get configuration defaults from config file.
var tableName = 'Table_Name';
var queueUrl = 'SQS_URL';
var dbClient = new aws.DynamoDB.DocumentClient();
var sqsClient = new aws.SQS();
// get config values from dynamodb - if the config values are found, then override existing values
// this will occur on every execution of the lambda which will allow real time configuration changes.
var updateConfig = function updateConfigValues(invokedFunction, cb) {
var params = {
TableName: "Table_NAME",
Key: {
"KEY": "KEY"
}
};
dbClient.get(params, function(err, data) {
if(err) {
console.log("ERR_DYNAMODB_GET", err, params);
}
else if(!data || !data.Item) {
console.log("INFO_DYNAMODB_NOCONFIG", params);
}
else {
queueUrl = data.Item.config.queueUrl;
tableName = data.Item.config.tableName;
}
return cb(err);
});
};
// save the email to dynamodb using conditional write to ignore addresses already in the db
var saveEmail = function saveEmail(messageBody, cb) {
var params = {
TableName:tableName,
Item:messageBody,
ConditionExpression : "attribute_not_exists(clickId)",
};
dbClient.put(params, function(err, data) {
cb(err, data);
});
};
var deleteMessage = function deleteMessage(receiptHandle, cb) {
var params = {
QueueUrl: queueUrl,
ReceiptHandle: receiptHandle
};
sqsClient.deleteMessage(params, function(err, data) {
cb(err, data);
});
}
exports.handler = function(event, context) {
updateConfig(context.invokedFunctionArn, function(err) {
if(err) {
context.done(err);
return;
}
console.log("INFO_LAMBDA_EVENT", event);
console.log("INFO_LAMBDA_CONTEXT", context);
sqsClient.receiveMessage({MaxNumberOfMessages:10 , QueueUrl: queueUrl}, function(err, data) {
if(err) {
console.log("ERR_SQS_RECEIVEMESSAGE", err);
context.done(null);
}
else {
if (data && data.Messages) {
console.log("INFO_SQS_RESULT", " message received");
var message = JSON.parse(data.Messages[0].Body);
var messageBody = message.Message;
messageBody = JSON.parse(messageBody);
// loops though the messages and replaces any empty strings with "N/A"
messageBody.forEach((item) => {
var item = item;
var custom = item.customVariables;
for (i = 0; i < custom.length; i++) {
if(custom[i] === ''){
custom[i] = 'N/A';
}
item.customVariables = custom;
}
for(variable in item) {
if(item[variable] === ""){
item[variable] = "N/A";
console.log(item);
}
}
var messageBody = item;
});
var messageBody = messageBody[0];
// Logs out the new messageBody
console.log("FIXED - ", messageBody);
// Checks for errors and delets from que after sent
saveEmail(messageBody, function(err, data) {
if (err && err.code && err.code === "ConditionalCheckFailedException") {
console.error("INFO_DYNAMODB_SAVE", messageBody + " already subscribed");
deleteMessage(message.MessageId, function(err) {
if(!err) {
console.error("INFO_SQS_MESSAGE_DELETE", "receipt handle: " + message.MessageId, "successful");
} else {
console.error("ERR_SQS_MESSAGE_DELETE", "receipt handle: " + message.MessageId, err);
}
context.done(err);
});
}
else if (err) {
console.error("ERR_DYNAMODB_SAVE", "receipt handle: " + message.MessageId, err);
context.done(err);
}
else {
console.log("INFO_DYNAMODB_SAVE", "email_saved", "receipt handle: " + message.MessageId, messageBody.Message);
deleteMessage(message.MessageId, function(err) {
if(!err) {
console.error("INFO_SQS_MESSAGE_DELETE", "receipt handle: " + message.MessageId, "successful");
} else {
console.error("ERR_SQS_MESSAGE_DELETE", "receipt handle: " + message.MessageId, err);
}
context.done(err);
});
}
});
} else {
console.log("INFO_SQS_RESULT", "0 messages received");
context.done(null);
}
}
});
});
}

AWS Lambda Test Cases

I am using the Github project here: https://github.com/danilop/LambdAuth/blob/master/LambdAuthCreateUser/index.js
I want to write tests so I can see if things get stored in the database correctly and to see the results of the functions.
I copied this Lambda function from the project above:
console.log('Loading function');
// dependencies
var AWS = require('aws-sdk');
var crypto = require('crypto');
var util = require('util');
var config = require('./config.json');
// Get reference to AWS clients
var dynamodb = new AWS.DynamoDB();
var ses = new AWS.SES();
function computeHash(password, salt, fn) {
// Bytesize
var len = 128;
var iterations = 4096;
if (3 == arguments.length) {
crypto.pbkdf2(password, salt, iterations, len, fn);
} else {
fn = salt;
crypto.randomBytes(len, function(err, salt) {
if (err) return fn(err);
salt = salt.toString('base64');
crypto.pbkdf2(password, salt, iterations, len, function(err, derivedKey) {
if (err) return fn(err);
fn(null, salt, derivedKey.toString('base64'));
});
});
}
}
function storeUser(email, password, salt, fn) {
// Bytesize
var len = 128;
crypto.randomBytes(len, function(err, token) {
if (err) return fn(err);
token = token.toString('hex');
dynamodb.putItem({
TableName: config.DDB_TABLE,
Item: {
email: {
S: email
},
passwordHash: {
S: password
},
passwordSalt: {
S: salt
},
verified: {
BOOL: false
},
verifyToken: {
S: token
}
},
ConditionExpression: 'attribute_not_exists (email)'
}, function(err, data) {
if (err) return fn(err);
else fn(null, token);
});
});
}
function sendVerificationEmail(email, token, fn) {
var subject = 'Verification Email for ' + config.EXTERNAL_NAME;
var verificationLink = config.VERIFICATION_PAGE + '?email=' + encodeURIComponent(email) + '&verify=' + token;
ses.sendEmail({
Source: config.EMAIL_SOURCE,
Destination: {
ToAddresses: [
email
]
},
Message: {
Subject: {
Data: subject
},
Body: {
Html: {
Data: '<html><head>'
+ '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />'
+ '<title>' + subject + '</title>'
+ '</head><body>'
+ 'Please click here to verify your email address or copy & paste the following link in a browser:'
+ '<br><br>'
+ '' + verificationLink + ''
+ '</body></html>'
}
}
}
}, fn);
}
exports.handler = function(event, context) {
var email = event.email;
var clearPassword = event.password;
computeHash(clearPassword, function(err, salt, hash) {
if (err) {
context.fail('Error in hash: ' + err);
} else {
storeUser(email, hash, salt, function(err, token) {
if (err) {
if (err.code == 'ConditionalCheckFailedException') {
// userId already found
context.succeed({
created: false
});
} else {
context.fail('Error in storeUser: ' + err);
}
} else {
sendVerificationEmail(email, token, function(err, data) {
if (err) {
context.fail('Error in sendVerificationEmail: ' + err);
} else {
context.succeed({
created: true
});
}
});
}
});
}
});
}
How do I test this?
I think you can test it with Jest.

fs.writefile only execute in last function in node js

My program has three functions shown below,
var userId = req.userId;
var appId = req.body.appId;
var main = 'temp/' + userId + '/templates/' + appId + '/css/main.css';
var color = req.body.color;
var font = req.body.font;
var fontSize = req.body.fontSize;
replaceThemecolor(color);
replaceFont(font);
replaceFontSize(fontSize);
function replaceThemecolor(color) {
fs.readFile(main, 'utf-8', function (err, data) {
var regex =/(\.made-easy-themeColor\s*{[^}]*color\s*:\s*)([^\n;}]+)([\s*;}])/;
var result = data.replace(regex, "$1" + color + "$3");
console.log(color);
fs.writeFile(main, result, 'utf-8', function (err) {
if (err) return console.log(err);
});
});
}
function replaceFont(font) {
fs.readFile(main, 'utf-8', function (err, data) {
var regex =/(\.made-easy-themeFont\s*{[^}]*font-family\s*:\s*)([^\n;}]+)([\s*;}])/;
var result = data.replace(regex, "$1" + font + "$3");
console.log(font);
fs.writeFile(main, result, 'utf-8', function (err) {
if (err) return console.log(err);
});
console.log(result);
})
}
function replaceFontSize(fontSize) {
fs.readFile(main, 'utf-8', function (err, data) {
var regex =/(\.made-easy-themeFontSize\s*{[^}]*font-size\s*:\s*)([^\n;}]+)([\s*;}])/;
var result1 = data.replace(regex, "$1" + fontSize + "em" + "$3");
console.log(fontSize);
fs.writeFile(main, result1, 'utf-8', function (err) {
if (err) return console.log(err);
});
});
}
In here only the last function executes all the time, when I execute them seperately they work well, but the problem arise when all the funtions execute at once. Is it a problem with fs.writeFile function? I want to execute three of this functions together, is there a way to do this? All the functions here work well when they execute seperately.
Your file functions are async. You cannot run them at the same time because they will conflict and one will overwrite the changes of the other. You must run one, then when it finishes, run the other.
Or, even better, only read the file once, the process the data with all your changes, then write it once.
If you were going to run them sequentially, then you would need to pass a callback to each of your functions that is called when it is done so then you know when to start the next function.
But, I think a better solution is to pass an array of replace instructions and just process all of them on one read and write of the file. I will work on a code example for that.
Here's a way to do all the updates in one read/write of the file and uses promises to know when the operation is done:
function updateFile(filename, replacements) {
return new Promise(function(resolve, reject) {
fs.readFile(filename, 'utf-8', function(err, data) {
if (err) {
reject(err);
} else {
// now cycle through and do all the replacements
for (var i = 0; i < replacements.length; i++) {
data = data.replace(replacements[i].regex, replacements[i].replacer);
}
fs.writeFile(filename, data, 'utf-8', function(err) {
if (err) {
reject(err);
} else {
resolve();
}
});
}
});
});
}
updateFile(main, [{regex: /(\.made-easy-themeColor\s*{[^}]*color\s*:\s*)([^\n;}]+)([\s*;}])/, replacer: "$1" + color + "$3"},
{regex: /(\.made-easy-themeFont\s*{[^}]*font-family\s*:\s*)([^\n;}]+)([\s*;}])/, replacer: "$1" + font + "$3"},
{regex: /(\.made-easy-themeFontSize\s*{[^}]*font-size\s*:\s*)([^\n;}]+)([\s*;}])/, replacer: "$1" + fontSize + "em$3"}]).then(function() {
// update done successfully
}, function(err) {
// error
});
With some more work, you could probably abstract out just the keywords from the regular expressions too so you only need to pass in the keywords, but I'll leave that to another time.
And here's a simplified version:
function updateFile(filename, replacements) {
return new Promise(function(resolve, reject) {
fs.readFile(filename, 'utf-8', function(err, data) {
var regex, replaceStr;
if (err) {
reject(err);
} else {
// now cycle through and do all the replacements
for (var i = 0; i < replacements.length; i++) {
regex = new Regex("(\\" + replacements[i].rule + "\\s*{[^}]*" + replacements[i].target + "\\s*:\\s*)([^\\n;}]+)([\\s*;}])");
replaceStr = "$1" + replacements[i].replacer + "$3";
data = data.replace(regex, replaceStr);
}
fs.writeFile(filename, data, 'utf-8', function(err) {
if (err) {
reject(err);
} else {
resolve();
}
});
}
});
});
}
updateFile(main, [
{rule: ".made-easy-themeColor", target: "color", replacer: color},
{rule: ".made-easy-themeFont", target: "font-family", replacer: font},
{rule: ".made-easy-themeFontSize", target: "font-size", replacer: fontSize + "em"}
], function() {
// update done successfully
}, function(err) {
// error
});
And, you don't have to use the promise at all if you don't want to know when it's all done or be able to return errors (which I wouldn't recommend, but the code is simpler).
function updateFile(filename, replacements) {
fs.readFile(filename, 'utf-8', function(err, data) {
var regex, replaceStr;
if (err) { return; }
// now cycle through and do all the replacements
for (var i = 0; i < replacements.length; i++) {
regex = new Regex("(\\" + replacements[i].rule + "\\s*{[^}]*" + replacements[i].target + "\\s*:\\s*)([^\\n;}]+)([\\s*;}])");
replaceStr = "$1" + replacements[i].replacer + "$3";
data = data.replace(regex, replaceStr);
}
fs.writeFile(filename, data, 'utf-8');
});
}
updateFile(main, [
{rule: ".made-easy-themeColor", target: "color", replacer: color},
{rule: ".made-easy-themeFont", target: "font-family", replacer: font},
{rule: ".made-easy-themeFontSize", target: "font-size", replacer: fontSize + "em"}
], function() {
// update done successfully
}, function(err) {
// error
});
Notice how easy it would be to add more replacements. You simply add one more line to the array you pass updateFile().
Node.js is inherently asynchronous. As such, you're doing three read operations in quick succession, and then trying to write to a file that's already file locked, or at the very least, when it was read, did not contain the write changes. I'd use something more like async's series or waterfall methods to solve this.
var async = require("async");
var userId = req.userId;
var appId = req.body.appId;
var main = 'temp/' + userId + '/templates/' + appId + '/css/main.css';
var color = req.body.color;
var font = req.body.font;
var fontSize = req.body.fontSize;
async.series({
replaceThemecolor: function(callback) {
fs.readFile(main, 'utf-8', function(err, data) {
var regex = /(\.made-easy-themeColor\s*{[^}]*color\s*:\s*)([^\n;}]+)([\s*;}])/;
var result = data.replace(regex, "$1" + color + "$3");
console.log(color);
fs.writeFile(main, result, 'utf-8', function(err) {
callback(err);
});
});
},
replaceFont: function(callback) {
fs.readFile(main, 'utf-8', function(err, data) {
var regex = /(\.made-easy-themeFont\s*{[^}]*font-family\s*:\s*)([^\n;}]+)([\s*;}])/;
var result = data.replace(regex, "$1" + font + "$3");
console.log(font);
fs.writeFile(main, result, 'utf-8', function(err) {
callback(err);
});
})
},
replaceFontSize: function(callback) {
fs.readFile(main, 'utf-8', function(err, data) {
var regex = /(\.made-easy-themeFontSize\s*{[^}]*font-size\s*:\s*)([^\n;}]+)([\s*;}])/;
var result1 = data.replace(regex, "$1" + fontSize + "em" + "$3");
console.log(fontSize);
fs.writeFile(main, result1, 'utf-8', function(err) {
callback(err);
});
});
}
}, function(err, results) {
// results is empty, but now the operation is done.
});

Using a query to search for a task_name, when function to find by id is already implemented

Okay so I'm trying to create a simple todo list, web api. I have the basic functions implemented and working properly but I'm trying to use a query to search by task_name as declared in my code, but no matter what I can't seem to get it functioning.
app.js
var express = require('express')
, routes = require('./routes')
, http = require('http')
, tasks = require('./routes/tasks')
, mongoose = require('mongoose');
// MongoDB Connection
mongoose.connect('mongodb://localhost/task_tracker');
var app = express();
app.configure(function(){
app.set('port', 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler());
});
app.get('/', routes.index);
app.get('/tasks', tasks.index);
app.get('/tasks/:id', tasks.show);
//app.get('/tasks/tasks?', tasks.search);
app.get('/tasks?', tasks.search);
app.post('/tasks', tasks.create);
app.put('/tasks', tasks.update);
app.del('/tasks', tasks.delete);
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port 3000");
});
tasks.js
var Task = require('../models/task').Task;
/*
* Tasks Routes
*/
exports.index = function(req, res) {
Task.find({}, function(err, docs) {
if(!err) {
res.json(200, { tasks: docs });
} else {
res.json(500, { message: err });
}
});
}
exports.show = function(req, res) {
var id = req.params.id;
Task.findById(id, function(err, doc) {
if(!err && doc) {
res.json(200, doc);
} else if(err) {
res.json(500, { message: "Error loading task." + err});
} else {
res.json(404, { message: "Task not found."});
}
});
}
exports.create = function(req, res) {
var task_name = req.body.task_name; // Name of task.
var description = req.body.task_description; // Description of the task
//Task.findOne({ name: task_name }, function(err, doc) { // This line is case sensitive.
Task.findOne({ name: { $regex: new RegExp(task_name, "i") } }, function(err, doc) { // Using RegEx - search is case insensitive
if(!err && !doc) {
var newTask = new Task();
newTask.name = task_name;
newTask.description = description;
newTask.save(function(err) {
if(!err) {
res.json(201, {message: "Task created with name: " + newTask.name });
} else {
res.json(500, {message: "Could not create task. Error: " + err});
}
});
} else if(!err) {
// User is trying to create a task with a name that already exists.
res.json(403, {message: "Task with that name already exists, please update instead of create or create a new task with a different name."});
} else {
res.json(500, { message: err});
}
});
}
exports.update = function(req, res) {
var id = req.body.id;
var task_name = req.body.task_name;
var task_description = req.body.task_description;
Task.findById(id, function(err, doc) {
if(!err && doc) {
doc.name = task_name;
doc.description = task_description;
doc.save(function(err) {
if(!err) {
res.json(200, {message: "Task updated: " + task_name});
} else {
res.json(500, {message: "Could not update task. " + err});
}
});
} else if(!err) {
res.json(404, { message: "Could not find task."});
} else {
res.json(500, { message: "Could not update task." + err});
}
});
}
exports.delete = function(req, res) {
var id = req.body.id;
Task.findById(id, function(err, doc) {
if(!err && doc) {
doc.remove();
res.json(200, { message: "Task removed."});
} else if(!err) {
res.json(404, { message: "Could not find task."});
} else {
res.json(403, {message: "Could not delete task. " + err });
}
});
}
exports.search = function(req, res) {
var name = req.query.name;
Task.findByName(name, function(err, doc) {
if(!err && doc) {
res.json(200, doc);
} else if(err) {
res.json(500, { message: "Error loading task." + err});
} else {
res.json(404, { message: "Task not found."});
}
});
}
task.js model
var mongoose = require('mongoose')
, Schema = mongoose.Schema;
var taskSchema = new Schema({
name : { type: String, required: true, trim: true, index: { unique: true } }
, description : { type: String, required: true }
, date_created : { type: Date, required: true, default: Date.now }
});
var task = mongoose.model('task', taskSchema);
module.exports = {
Task: task
};
Basically i am just trying to use a similar function to that of my search by id function but i know i can't just use parameters and I can't figure out how to get the query working. Any help would be appreciated. If you can't tell I'm using Node.js, Express and Mongodb.
TL;DR: You need to merge tasks.index and tasks.search route, ie. like this:
tasks.index = function(req, res, next) {
if (req.query.name !== undefined) {
// pass on to next handler
return next();
}
// the rest of your tasks.index.
});
And adjust the Router setup like this:
app.get('/tasks', tasks.index);
app.get('/tasks', tasks.search);
Why? Query string is not part of the route. So '/tasks?' is just a regex for /tasks+1 character, but not for a query string - query string is not a part of the route match.
More specifically, you have in your routes this:
app.get('/', routes.index);
app.get('/tasks', tasks.index);
app.get('/tasks?', tasks.search);
That last, /tasks? route will not get registered like you seem to expect. The question mark isn't representing query string processing, it's a part of the route regex, and basically means that you'd catch anything that adds one character to /tasks route, ie /tasksa, /tasksb, /tasks7 etc.
So, 7 characters, first six of which are known, the last is different, query string not included.
You cannot parse query strings in the router, it's in the individual controllers, kind of like this:
tasks.search = function(req, res) {
if (req.query.name) {
// you have the name query
}
// etc.
}
Additional advice is, what is usually done on a REST API is have the global tasks.index, like you have there, and add two things on it: paging and filter/searching.
If you want just one result
Paging is page=3&limit=10 (3rd page, 10 items per page), and filtering/sorting/searching is what you want. And depending how you want it, that's how you expose it.
Ie. you might want to sort by name:
if (req.query.sort === 'name:desc') {
mongoCursor.sort = {name: -1};
}
Or something of a sort.
So you'd probably have a search, or maybe directly a name query parameter, like this:
GET /tasks?name=<search term>
And the name param is usually optional.
So your req would list all things, and if name query string is set, it would filter by name first.
Your query building process can then look like this:
tasks.index = function(req, res) {
var query = {};
if (req.query.name) {
query.name = req.query.name;
}
Tasks.find(query, ...);
In that case, you don't need helpers on the Task model.
I found this method also works.
/**
* Module dependencies.
*/
var express = require('express'),
cors = require('cors'),
routes = require('./routes'),
http = require('http'),
tasks = require('./routes/tasks'),
mongoose = require('mongoose'),
search = require('./routes/search');
var Task = require('./models/task').Task;
// MongoDB Connection
mongoose.connect('mongodb://localhost/task_tracker');
var app = express();
app.configure(function() {
app.set('port', 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.urlencoded());
app.use(express.json());
app.use(cors());
});
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
var corsOptions = {
origin: 'http://localhost:3000'
};
app.get('/', routes.index);
app.get('/tasks', tasks.index);
//app.get('/search', tasks.FindByQuery);
//app.get('/tasks/:task.:name?', task.FindByQuery);
app.get('/search', function(req, res, next) {
var query = req.query
//res.send(query['name']);
Task.findOne({name: query['name']}, function(err, doc) {
if(!err && doc) {
res.json(200, doc);
} else if(err) {
res.json(500, { message: "Error loading task." + err});
} else {
res.json(404, { message: "Task not found."});
}
});
//res.end(JSON.stringify(query));
});
app.get('/tasks/:id', tasks.show);
app.post('/tasks', tasks.create);
app.put('/tasks', tasks.update);
app.del('/tasks', tasks.delete);
http.createServer(app).listen(app.get('port'), function() {
console.log("Express server listening on port 3000");
});