I'm working on an application using Meteor and MongoDB where I'm attempting use nested callbacks to access a newly inserted document as seen below. However I keep getting an error where there is no matching document in the database even though I'm in the successful callback of the insert statement. I'm not sure as to why Mongo can't find the document I just inserted. I understand that the methods are asynchronous, but I assumed that the callback would allow me to access the newly inserted document once the find function returns. I attempted to place the find outside of the insert statement with its own callback and got the same error.
I've attached the error message as well. Any help on this matter would be greatly appreciated!
insertEntryForm.call(entryFormObj, (error, result) => {
if (error) {
console.log(error);
toastr['error'](error.reason);
}
else {
toastr['success']("Entry form created!");
EntryForms.find({_id: result}, function(err, res) {
console.log(res);
});
}
}
);
From the documentation and the examples provided by Inserting and updating - MongoDB the second argument for the insert callback is the object inserted and in your find you're looking for a document with result , it should be result._id , so this should work :
EntryForms.find({_id: result._id}, function(err, res) {
Turns out the issue had to do with the way in which I was publishing/subscribing to my object within Meteor. I registered my subscription in my router.js file and was then able to access my collection as expected. Chalk this one up to my small experience with Meteor.
Related
Hopefully someone can help me solve what I am sure is a rookie mistake.
I am trying to adapt an authentication app originally based on mongodb, to work with sequelize\MSSQL instead, but getting tied up in knots with trying to blend a callback-based working example with
seqeulize's promised based approach.
Both MongoDb\Sequelize offer a findOne() method.
Original (working) code referencing MongoDb collection:
module.exports.getUserByUsername = function(username,callback){
var query = {username: username};
User.findOne(query,callback);
}
The callback in this case is from a separate calling module and is the standard verify password of passport.js's local-strategy.
Since the sequelize findOne() method expects a where clause I had hoped the following would be an out of the box solution:
module.exports.getUserByUsername = function(username,callback){
var query = {where: {username: username}};
User.findOne(query,callback);
}
This outputs a functional query into the console.log, but the callback doesn't fire, so the page hangs.
Looking at the respective API docs it appears that sequelize findOne() is exclusively promise based whereas MongoDb findOne() returns a promise only if where a callback function is not passed to the findOne() method, otherwise flow is handed to the callback when one is provided as is the case with the working example.
I tried the following adaptation to work with a sequelize promise (and quite a number of permutations thereof calling the callback function within the .then() clause etc)., but all fail with a hanging page: :
module.exports.getUserByUsername = function(username,callback){
var query = {where: {username: username}};
return User.findOne(query).then(user => {
console.log(user.get({ plain: true }));
return user.dataValues;
//callback(user.dataValues)
}).finally(() => {
console.log('done!')
});
}
The console.log(user.get()) spools out the correct details showing the database query executed correctly returning the required user data, so I feel that I'm very near to finding the right syntax to delivering this back to the passport callback.
Any help would be much appreciated!
Add raw property to true like this, and you can get the user object
User.findOne({ where : {username:username}, raw: true}).then( user => {
return user
})
I'm trying to drop a non existant collection and I get the following error:
MongoError: ns not found.
In a similar question, there is a link to the mongo code which shows that this is the expected behaviour:
MongoError: ns not found when try to drop collection
However, according to the mongo documentation, this method should return false if the collection does not exists:
https://docs.mongodb.com/manual/reference/method/db.collection.drop/#db.collection.drop
What am I missing?
Server version - 3.6.5, mongodb client (javascript) - 3.0.21
The commands I used:
await mongodb.collection('colname').drop()
and
mongodb.collection('colname').drop((err, res) => {
console.log('err: ' + err + ', res: ' + res) // doesn't get called
})
You link refers to the command interface of the mongo client. It uses javascript but is an application that has its own REPL. The documentaion is correct.
The command you are using is from the official mongodb node package. The behavior of these commands are different than those on the mongo client. The documentation concerning your usage is here: http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#drop
BTW, the first parameter is an option object, the second would be the callback.
The callback you provide is only called on a successful mongodb query. When the collection does not exist (like in this case), the callback is not executed. But this function returns a promise, which can be used to handle any error:
mongodb.collection('colname').drop().then(function () {
// success
}).catch(function () {
// error handling
})
When receiving JSON data via websockets, I'm trying to feed this data into a mongodb within meteor. I'm getting the JSON data fine, but when trying to find whether the data already exists in the database, I keep getting the error: "[ 'Parse error: Can\'t wait without a fiber' ]'.
binance.websockets.miniTicker(markets => {
//we've got the live information from binance
if (db.Coins.find({}).count() === 0) {
//if there's nothing in the database right now
markets.forEach(function(coin) {
//for each coin in the JSON file, create a new document
db.Coins.insert(coin);
});
}
});
Can anyone point me in the right direction to get this cleared up?
Many thanks,
Rufus
You execute a mongo operation within an async function's callback. This callback is not bound to the running fiber anymore. In order to connect the callback to a fiber you need to use Meteor.bindEnvironment which binds the fiber to the callback.
binance.websockets.miniTicker(Meteor.bindEnvironment((markets) => {
//we've got the live information from binance
if (db.Coins.find({}).count() === 0) {
//if there's nothing in the database right now
markets.forEach(function(coin) {
//for each coin in the JSON file, create a new document
db.Coins.insert(coin);
});
}
}));
You should not require to bind to the function within the forEach as they are not async.
Related posts on SO:
Meteor.Collection with Meteor.bindEnvironment
Meteor: Calling an asynchronous function inside a Meteor.method and returning the result
Meteor wrapAsync or bindEnvironment without standard callback signature
What's going on with Meteor and Fibers/bindEnvironment()?
I am encountering a weird issue here...
After I seem to successfully insert some data into my db.collection I cant seem to get it to reflect using db.collection.find().fetch().
Find below the code I insert into my chrome console:
merchantReviews.insert({merchantScore: "5.5"}, function() {
console.log("Review value successfully inserted");
});
This yields:
"9sd5787kj7dsd98ycnd"
Review value successfully inserted
I think returned value "9sd5787kj7dsd98ycnd" is an indication of a successful db collection insert. Then when I run:
merchantReviews.find().fetch()
I get:
[]
Can anyone tell me what is going on here?
Looking forward to your help.
There are two possibilities here: either the insert fails on the server even though it passes on the client, or you haven't subscribed to your collection.
In case the insert fails on server (most likely due to insufficient permissions, if you have removed the insecure package but have not declared any collection.allow rules), the client code still returns the intended insert ID (in your case, "9sd5787kj7dsd98ycnd"). The callback is called once the server has confirmed that the insert has either failed or succeeded. If it has failed, the callback is called with a single error argument. To catch this, you can instead insert the document like this:
merchantReviews.insert({merchantScore: "5.5"}, function(error) {
if (error) {
console.error(error);
} else {
console.log("Review value successfully inserted");
}
});
If this still logs successful insert, then you haven't subscribed to the collection, and you have removed the autopublish package. You can read about Meteor publish-subscribe system here. Basically, you have to publish the collection in server-side code:
Meteor.publish('reviews', function () {
return merchantReviews.find();
});
And in server code (or your js console) you need to subscribe to the collection with Meteor.subscribe('reviews'). Now calling merchantReviews.find().fetch() should return all documents in the collection.
I have a User controller that has a create method that checks the database for email and username uniqueness before creating the user (this is to work-around a bug in the mongodb adpater for SailsJS that doesn't honour the unique attribute flag - version 0.10.5).
The code looks like the following:
User.find({ email: req.body.email }, function (err, user) {
if(user) {
return res.badRequest('Unique email constraint. Email is already used.');
}
});
User.create(req.body).exec(function (err, user) {
// Code to catch and manage err or new user
}
What I expect is that if the email already exists in the database (mongodb), to send a 400 using res.badRequest(), then execution to end.
What happens is that the response is sent, but then control moves to User.create() - execution doesn't end. I suspect that return res.badRequest is returning control back to the calling function (User.findOne), and execution continues from there.
I tried using res.badRequest().end() but that leaves the client hanging (there is no response), and using res.end() after the return res.badRequest() generated 'header send' errors.
How do I have execution of this request end if an existing email is found?
First of all, your findOne is here a find. That's not related to your problem, but it is slightly confusing, and you should ensure you are getting data in the format you expect.
As for finishing the request after marking it bad, I have not used sails, but I was able to end execution in the past by using res.send(). EDIT: after looking at the docs, it seems this is done for you by .badRequest(), so ignore that part.
That said, even THAT is not actually your problem. Your problem is that you start an asynchronous User.find(), and then you immediately start running User.create() (also asynchronously), and so your request doesn't get marked bad until after you have already attempted to create a new user.
What you need to do is one of two things:
Use promises (NOTE: this is how it works for Mongoose; Sails may be different) to only run User.create() after User.find() has completed. e.g;
var userQuery = User.findOne({ email: req.body.email }).exec();
userQuery.addBack(function(err, user) {
if(!!user) res.badRequest('...');
else create_user();
});
Put your user creation logic inside of your findOne block. e.g.;
User.findOne({ email: req.body.email }, function(err, user) {
if (user) { // or perhaps you want if (!err)
User.create(...);
} else {
// handle error
}
});
Personally, I would advise that you use promises (especially later, when you have long chains of requests happening one on top of the other), but take your pick.