I have had a similar error before but that was caused by a syntax error in the .run statement.
I have looked this code over and over and can't find a syntax so I think something else is going on. This function is called by the passport deserializer and the value of "id" was confirmed using node-inspector. however, no matter which type of MATCH query I use, I get the same .catch error.
I have tried WHERE option and the direct option...they both work in the neo4j browser. Can someone see what I am not seeing
router.getUserByID = function (id, callback) {
session
.run ("MATCH (user {id(user) : {paramUserID}}) RETURN user",{paramUserID: parseInt(id)})
.then (function(result)
{
if ( !result.records[0])
{
console.log("unknow user by id");
session.close();
if (typeof callback==="function") {
return callback(null,false);
}
} // end of if not found
else
{
console.log("user by id found");
session.close();
if (typeof callback === "function") {
return callback(null,result);
}
}
})
.catch(function(err)
{
console.log("catch error: "+err);
});
} // end of get user by id
You cannot reference the Neo4j id of the node that way, you have to use a WHERE clause:
MATCH (user) WHERE id(user) = {paramUserID} RETURN user;
If you have an application id (almost always a good idea), then you could do:
MATCH (user {uuid: {paramUuid}}) RETURN user;
It would be better with a label though, because different entities could have the same id, and you can use a unicity constraint (which also indexes the values, so the query is faster):
CREATE CONSTRAINT ON (n:User) ASSERT n.uuid IS UNIQUE;
// Later
MATCH (user:User {uuid: {paramUuid}}) RETURN user;
Related
I keep getting an error: TypeError: Cannot read property 'doors' of null. I want to be able to set doors to be nullable, as to be able to avoid this error and simply hit the error response and return 404. However, I am not sure how to do this?
Here is my code:
Data.findOne({
'_id':'6182544c20d538aefe49def0',
'doors.id':doorId
}, {
'doors.$':1
}, function(err, data) {
if (err) {
res.status(404).send('No Matching Door Found')
} else if (data.doors[0].status === 'open') {
res.status(401).send('Door already unlocked')
} else {
res.status(200)
}
})
The error is hit on the third line, where It cannot find a doors object where the ID is equal to doorId.
I have tried setting doors.id to !doors.id, however, this then kept hitting the 404 regardless of what was being entered.
Any help is appreciated, thank you.
Well it seems that your entire query is wrong.
I would suggest first to try this query for your needs:
Data.findOne({
'_id':'6182544c20d538aefe49def0',
'doors.id':doorId
}, {
'doors.$':1
}).exec(function(err, data) {
if (err) {
res.status(404).send('No Matching Door Found')
} else if (data.doors[0].status === 'open') {
res.status(401).send('Door already unlocked')
} else {
res.status(200)
}
})
Then I recommend you to read more about MongoDB and Mongoose.
I have a question about handling exceptions/errors. Consider this implementation using a try/catch. This is certainly one option, but I've also heard try/catch can be a little heavy-handed.
Option 1:
async function updateCustomerRegion(params, auth) {
const { id, region } = params;
const Customer = await CustomerModel();
const filter = { _id: id };
const update = { region: region };
try {
const customer = await Customer.findOneAndUpdate(filter, update, { new: true })
.lean()
.exec();
} catch (error) {
console.log(error);
throw "Error: Unable to update customer";
}
return {
count: customer ? 1 : 0,
data: customer
};
}
Another option is this implementation where I just throw an error if "customer" is false:
Option 2:
async function updateCustomerRegion(params, auth) {
const { id, region } = params;
const Customer = await CustomerModel();
const filter = { _id: id };
const update = { region: region };
const customer = await Customer.findOneAndUpdate(filter, update, { new: true })
.lean()
.exec();
if (!customer) throw "Error: Unable to update customer";
return {
count: customer ? 1 : 0,
data: customer
};
};
My question is, how functionally equivalent are these two implementations? Will Option #1 handle more than Option #2, or is using try/catch a little heavy-handed in this instance?
Option 1 As far as I know, it's best practice to wrap async/await with try/catch, anywhere if anything goes wrong then exceptions/errors will be handled in catch block i.e; you can throw custom exceptions in catch block along with any generic exceptions.
In your Option 2, I don't think code would reach if (!customer) throw "Error: Unable to update customer"; if there is an exception/error it would return from above line and error out from there with a non-user friendly exception in response - wouldn't go to caller and return a response(either expected or user friendly error message). if(!customer) is just like your function executed well & you're checking on the return object is not valid - if empty do return no customer found or something it's not equal to catching errors. So to be precise it's more like functionality check rather than exception handling. Ex :-
Combining both for better implementation :
async function updateCustomerRegion(params, auth) {
const { id, region } = params;
/* here you are basically validating region is string or not and returning from here, with out any further exception (just a basic example)*/
if (!region && region !== typeof ('')) throw "Error: invalid region";
const Customer = await CustomerModel();
const filter = { _id: id };
const update = { region: region };
try {
const customer = await Customer.findOneAndUpdate(filter, update, { new: true })
.lean()
.exec();
/* Here as well a validation check not to execute further assuming your DB call will respond with empty object*/
if (Object.entries(customer).length !== 0 && customer.constructor === Object) throw "Error: Unable to update customer - no customer found";
/* or */
if (Object.entries(customer).length !== 0 && customer.constructor === Object) return { count: 0, data: [] };
} catch (error) {
console.log(error);
/* Basically this is just an example to show you can check something here & do custom exceptions */
if (error.stack === 'operation exceeded time limit') {
throw "Error: Unable to update due to timeout or someother";
} else {
throw "Error: Unable to update";
}
}
/* more logic to add more fields and return */
return {
count: 1,
updatedBy: 'name',
reason: 'just updated like that',
data: customer
};
}
They are not functionally equivalent.
Implementation #1 will throw an error if findOneAndUpdate is actually throwing an error itself, regardless of its return value (it's not returning a value at all in this case). Here you are handling exceptions that have been thrown in findOneAndUpdate or that have bubbled from a dependency of it.
Implementation #2 will throw an error if findOneAndUpdate doesn't throw an error but returns a falsy value. Here you are deciding that the return value is unexpected, and you cannot proceed with the method execution, hence throwing an exception. In this case, if findOneAndUpdate throws an exception for whatever reason, you are not handling it and it will bubble up to updateCustomerRegion callee, possibly crashing your application.
As a rule of thumb, I would suggest to try/catch all your async calls whenever it makes sense (e.g. performing API calls, queries, etc...). You can also combine the two, handling the exception and throwing on falsy returns might make complete sense in your use case.
Also, I would advise against throwing raw strings but to always rely on an actual instance of an Error class (either typescript stock errors or a custom one).
I have a delete route for my api that deletes tokens stored in our mongodb. I am currently writing a check that makes sure the token is not associated with another object before it is processed for deletion.
function checkTokenIsNotUsed(req) {
console.log('TEST ' + req.params.token);
objectDB.findObject('artefact', {"data.token": req.params.token})
.then(function(result) {
console.log('findObject result' + result);
if (isDefined(result)) {
console.log('Artefact Exists');
serverError(res, 'Cannot delete token as it is associated with an artefact');
} else {
console.log('Token not being used by an artefact, okay for deletion');
};
})
.catch(function(err){
console.error('Token CHECK DELETE error: '+err.message);
serverError(res, 'err.message');
});
return(result)
};
//
// Token deletion
//
app.delete('/:token', function(req, res, next) {
checkTokenIsNotUsed(req)
.then(function(results){
return tokenModel.findOne({token: req.params.token});
})
As it stands, when I hit the route the checkTokenIsNotUsed function is called, and prints 'TEST + <token>' to the console, and then kicks out to cannot read property 'then' of undefined.
I have checked my query in the mongo shell independently of the platform interface that I am using and the query works as expected. The api route also works as expected without the checkTokenIsUsed function active.
Any ideas as to why the promise for objectdb.findObject() is not returning a result? It is intended to return a list of objects or nothing at all, and does as expected in other locations in this file.
-findObject is properly exported + imported from its respective location
-the query is correctly structured and works in mongo shell.
-the token itself is being printed just before this function is run, so checkTokenIsNotUsed is getting called and being executed.
-I don't really care that the conditional is just printing to the console at the moment, as my objective right now is to merely enter into that part of the function.
EDIT added
findObject = function(objType, query, options) {
return new Promise(function(resolve,reject) {
var populateOptions;
var findQuery = {};
var findOptions = {
sort: 'metaData.createTS',
page: 1,
limit: 50
};
var objectDef = getObjectDef(objType);
if (!isDefined(objectDef)) return resolve(null);
// Make sure query exists and has objType set
if (isDefined(query)) findQuery = query;
if (!isDefined(findQuery.objType)) findQuery.objType = objType;
if (isDefined(options)) {
if (isDefined(options.sort)) findOptions.sort = options.sort;
if (isDefined(options.page)) findOptions.page = toInt(options.page);
if (isDefined(options.limit)) findOptions.limit = toInt(options.limit);
}
if (isDefined(objectDef.populate)) populateOptions = objectDef.populate;
else populateOptions = "";
objectDef.model.find(findQuery, null, findOptions)
.populate(populateOptions)
.exec(function(error, list) {
if (error) reject(error);
else resolve(list);
});
});
};
So I have a function that when you pass a username as an argument it queries a MongoDB database and returns the document containing that username. So in the function, I check to see if the document exists containing the username, and if it doesn't I return the document that has an empty string as the username. So kind of like, return default if doesn't exist. So I assume that if it doesn't find a matching document it returns an undefined object.
Ideally, I want a function that when called will either return a default document retrieved from a database when the username doesn't exist or return the corresponding document for the username passed as an argument. Maybe the problems are trying to read or return variables before they exist because of the asynchronous nature of the calls.
I really don't think major restructuring of the code is a good idea, because I'm trying to work with three asynchronous libraries and connect them all together. I have multiple asynchronous classes in recursive processing functions.
getContext(username = '') {
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/tc-db', function (err, db) {
if (err) {
console.log(err);
} else {
db.collection('chatters').findOne({ username: username }, function (err, results) {
if (err) {
throw err;
} else if (results === undefined) {
db.collection('chatters').findOne({ username: '' }, function (err, results) {
console.log('Notifier');
console.log('Get if Null: ' + JSON.stringify(results));
return JSON.stringify(results.context);
});
} else {
console.log('Notifier 2');
return JSON.stringify(results.context);
}
});
}
});
}
The actual error I'm getting alot when running the function, especially with a username that doesn't exist in the database is "Can't read property 'context' of null". Thank you guys so much for any help you can offer.
I have an express route which takes in some parameters, queries the database, and then returns some response.
I am using sequelize to query the db:
router.get('/query', function(req,res) {
var name = req.params.name;
var gid = req.params.gid;
// Query the db
models.user.find({ where: { name: name }}).then(function(user) {
models.group.find({ where: { id: gid }}).then(function(group) {
// if user found, return data to client
if (user) {
res.json({"user": user, "group": group});
}
});
}).catch(function(error) {
// catch any errors from db query
res.status(500).json({"error":error});
});
// Return a server error for any other reason
// This causes ERROR
res.status(500).json({"error":"Something went wrong. Check your input."});
});
But I keep getting the error on the last line:
Can't set headers after they are sent
It seems like the last line is ALWAYS run, even if it finds a user (which should return data to the client and be done).
Why doesn't res.json(..) immediately return to the client when a user is found? Since headers were already set, when the last line runs, it throws that error.
You need to only conditionally return an error. The line:
res.status(500).json({"error":"Something went wrong. Check your input."});
is always getting executed. The reason for this is that the function you pass to the find method is only called later in the event loop after the db responds. This means that when that call back is called you have already set the error on the response.
Your should either remove that line or decide when you want to return an error but don't return an error every time.
Remember javascript is asynchronous.
As soon you call this function
models.user.find({ where: { name: name }})
That last line is executed:
res.status(500).json({"error":"Something went wrong. Check your input."});
It seems you are trying to cater for 2 scenarios:
Bad request data from client - i.e. no gid given
Internal server errors - i.e. error with the database
I would recommend changing your catch function to something like this:
.catch(function(error) {
// catch any errors from db query
if (err === "Unable to connect to database") {
return res.status(500).json({ error: "There was an internal error"})
}
res.status(400).json({"error": "Bad input, please ensure you sent all required data" });
});
Have a read up on the list of standard HTTP status codes:
http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
What #bhspencer said is right. You have to remove that last line.
That line probably gets executed before any query in the database.
You need to implement a return in
models.user.find({ where: { name: name }}).then(function(user) {
models.group.find({ where: { id: gid }}).then(function(group) {
// if user found, return data to client
if (user) {
res.json({"user": user, "group": group});
return;
}
});
}).catch(function(error) {
// catch any errors from db query
res.status(500).json({"error":error});
return;
});
Actually res.json( does not end the processing of node.js code execution without return statement.