Why doesn't my db.collection.insert work? - mongodb

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.

Related

[ 'Parse error: Can\'t wait without a fiber' ]' When trying to do find within Metor

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()?

MongoDB Callback Error

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.

Empty response on long running query SailsJS

I'm currently running SailsJS on a Raspberry Pi and all is working well however when I execute a sails.models.nameofmodel.count() when I attempt to respond with the result I end up getting a empty response.
getListCount: function(req,res)
{
var mainsource = req.param("source");
if(mainsource)
{
sails.models.gatherer.find({source: mainsource}).exec(
function(error, found)
{
if(error)
{
return res.serverError("Error in call");
}
else
{
sails.log("Number found "+found.length);
return res.ok({count: found.length});
}
}
);
}
else
{
return res.ok("Error in parameter");
}
},
I am able to see in the logs the number that was found (73689). However when responding I still get an empty response. I am using the default stock ok.js file, however I did stick in additional logging to try to debug and make sure it is going through the correct paths. I was able to confirm that the ok.js was going through this path
if (req.wantsJSON) {
return res.jsonx(data);
}
I also tried adding .populate() to the call before the .exec(), res.status(200) before I sent out a res.send() instead of res.ok(). I've also updated Sails to 11.5 and still getting the same empty response. I've also used a sails.models.gatherer.count() call with the same result.
You can try to add some logging to the beginning of your method to capture the value of mainsource. I do not believe you need to use an explicit return for any response object calls.
If all looks normal there, try to eliminate the model's find method and just evaluate the request parameter and return a simple response:
getListCount: function(req, res) {
var mainsource = req.param("source");
sails.log("Value of mainsource:" + mainsource);
if (mainsource) {
res.send("Hello!");
} else {
res.badRequest("Sorry, missing source.");
}
}
If that does not work, then your model data may not actually be matching on the criteria that you are providing and the problem may lie there; in which case, your response would be null. You mentioned that you do see the resulting count of the query within the log statement. If the res.badRequest is also null, then you may have a problem with the version of express that is installed within sailsjs. You mention that you have 11.5 of sailsjs. I will assume you mean 0.11.5.
This is what is found in package.json of 0.11.5
"express": "^3.21.0",
Check for any possible bugs within the GitHub issues for sailsjs regarding express and response object handling and the above version of express.
It may be worthwhile to perform a clean install using the latest sailsjs version (0.12.0) and see if that fixes your issue.
Another issue may be in how you are handling the response. In this case .exec should execute the query immediately (i.e. a synchronous call) and return the response when complete. So there should be no asynchronous processing there.
If you can show the code that is consuming the response, that would be helpful. I am assuming that there is a view that is showing the response via AJAX or some kind of form POST that is being performed. If that is where you are seeing the null response, then perhaps the problem lies in the view layer rather than the controller/model.
If you are experiencing a true timeout error via HTTP even though your query returns with a result just in time, then you may need to consider using async processing with sailjs. Take a look at this post on using a Promise instead.

Transforming DB Collections in Meteor.publish

Hopefully this question is not too long but I am trying to include as much details as possible in what I did..
I am trying to figure out how to implement logic in Meteor.publish() that takes data from the DB, changes all the values in a column and makes the updated collection available for client-side subscription.
Specifically, I have a table that stores messages between users and the recipient is identified by his userId. I would like to replace the userId with his actual phone number which should be available in the Meteor.users table.
When I looked it up online I saw suggestions to use transform but my understanding is that it's not reactive.. I then learned about map but discovered that it returns an array which breaks the Meteor.publish() method. Finally I found something that uses forEach and self.added() and self.ready() so my code currently looks like this:
Meteor.publish("myMessages", function () {
var self = this;
Messages.find({
$or: [
{ senderId: this.userId },
{ recipientId: this.userId }
]
}).forEach(function(m) {
m.recipientId = Meteor.users.findOne({ _id: m.recipientId }).username;
console.log("adding msg to collection:");
console.log(m);
self.added("Messages", m._id, m);
});
self.ready();
});
The log messages look right and when Meteor restarts it prints all the messages from the DB related to the user where the recipient is replaced correctly with the phone number. However, on the client side when I try to run Messages.findOne(msgId) (with an id I verified exists by selecting it directly in mongo shell) I get undefined back and furthermore, running Messages.find() through developer tools in the browser returns undefined as well although I expected the messages that showed up in the logs to be available..
I feel that this is a basic use case but I am not able to make this work.. any help is appreciated!
"You can transform a collection on the server side like this:"
https://stackoverflow.com/a/18344597/4023641
It worked for me.
Unfortunately, changes in users collection will not update reactively these custom fields.

How to send final response from findOne() callback?

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.