I am trying to learn Node.js and using MongoDB.
I got an insert working correctly and can insert as many objects as I want, however I cannot seem to query them at all.
I have tried using every technique posted here and none of them return any of my objects.
I have verified via the Mongo console that the objects exist but I just can't query them and I am absolutely lost as to why.
Here is the current code I'm using to query:
User.findOne({ 'user.name': 'James' }, function(user){
console.log("Got " + user);
res.send(user);
});
Help?
EDIT
The above code returns "null".
Nearly every time I post a question on SO lately I seem to find the answer myself within 15 minutes.
The answer to this one, is that my callback function is only accepting 1 argument of "user". The first argument in the callback is any Errors that are raised, so obviously there are no errors raised.
Changing the callback to this fixes it:
function(err, user) {
}
Related
Since version 3.6 MongoDB requires the use of cursor or explain in aggregate queries. It's a breaking change so I have to modify my earlier code.
But when I add cursor or explain to my query, the request simply enters an endless loop and MongoDB never responds. It doesn't even seem to time out.
This simple aggregation just hangs the code and never responds:
db.collection('users').aggregate([{ $match: { username: 'admin' }}],
{ cursor: {} },
(err, docs) => {
console.log('Aggregation completed.');
});
I can replace { cursor: {} } with { explain: true } and the result is the same. It works perfectly under older MongoDB versions without this one parameter.
Without cursor or explain I get this error message:
The 'cursor' option is required, except for aggregate with the explain argument
I'm not the only one who ran into this:
https://github.com/nosqlclient/nosqlclient/issues/419
OK, this was a little tricky, but finally it works. Looks like there are some major breaking changes in MongoDB's Node.js driver which nobody bothered to tell me.
1. The Node.js MongoDB driver has to be upgraded. My current version is 3.0.7.
2. The way how MongoDB connects has been changed, breaking any old code. The client connection now returns a client object, not merely the db. It has to be handled differently. There is a SO answer explaining it perfectly:
db.collection is not a function when using MongoClient v3.0
3. Aggregations now return an AggregationCursor object, not an array of data. Instead of a callback now you have to iterate through it.
var cursor = collection.aggregate([ ... ],
{ cursor: { batchSize: 1 } });
cursor.each((err, docs) => {
...
});
So it seems you have to rewrite ALL your db operations after upgrading to MongoDB 3.6. Yay, thanks for all the extra work, MongoDB Team! Guess that's where I'm done with your product.
is there a way to make synchronous queries to MongoDB?
I'd like to run some code only after I've retrieved all my data from the DB.
Here is a sample snipped.
Code Snippet A
const brandExists = Brands.find({name: trxn.name}).count();
Code Snippet B
if(brandExists == 0){
Brands.insert({
name:trxn.name,
logo:"default.png",
});
Trxs.insert({
userId,
merchant_name,
amt,
});
}
I'd like Code snippet B to run only after Code Snippet A has completed its data retrieval from the DB. How would one go about doing that?
You can use simple async function async function always returns a promise.
const brandExists;
async function brandExist() {
brandExists = Brands.find({
name: trxn.name
}).count();
}
brandExist().then(
// Your Code comes here
if (brandExists == 0) {
Brands.insert({
name: trxn.name,
logo: "default.png",
})
Trxs.insert({
userId,
merchant_name,
amt,
});
});
I don't think using an if statement like the one you have makes sense: the queries are sent after each other; it is possible someone else creates a brand with the same name as the one you are working with between your queries to the database.
MongoDB has something called unique indexes you can use to enforce values being unique. You should be able to use name as a unique index. Then when you insert a new document into the collection, it will fail if there already exists a document with that name.
https://docs.mongodb.com/manual/core/index-unique/
In Meteor, MongoDB queries are synchronous, so it already delivers what you need. No need to make any changes, snippet B code will only run after snippet A code.
When we call a function asynchronous we mean that when that function is called it is non-blocking, which means our program will call the function and keep going, or, not wait for the response we need.
If our function is synchronous, it means that our program will call that function and wait until it's received a response from that function to continue with the rest of the program.
Meteor is based in Node, which is asynchronous by nature, but coding with only asynchronous functions can origin what developers call "callback hell".
On the server side, Meteor decided to go with Fibers, which allows functions to wait for the result, resulting in synchronous-style code.
There's no Fibers in the client side, so every time your client calls a server method, that call will be asynchronous (you'll have to worry about callbacks).
Your code is server-side code, and thanks to Fibers you can be assure that snippet B code will only run after snippet A code.
I'm having trouble getting my aftersave cloud function to increment a value in another data table. The Parse documentation is a bit confusing on this front.
I have a table called "CandidateVotes" that stores a row for each vote on a "candidate" - and when a new vote row is saved, I would like to increment the total votes count stored in a different table called "CategoryCandidates" which has a row for each "candidate".
So the relevant information:
Votes table is called "CandidateVotes"
Candidates table is called "CategoryCandidates"
Total votes count column in CategoryCandidates table is called "votes"
Here's my Parse aftersave cloud function:
Parse.Cloud.afterSave("CandidateVotes", function(request) {
query = new Parse.Query("CategoryCandidates");
query.get(request.object.get("CategoryCandidates").objectID, {
success: function(candidate) {
candidate.increment("votes");
candidate.save();
},
error: function(error) {
console.error("Got an error" + error.code + " : " + error.message);
}
});
});
When a new vote is saved, this is the error that I'm getting in my cloud code logs:
E2015-09-04T15:49:23.553Z]v9 after_save triggered for CandidateVotes as master:
Input: {"object":{"candidateID":{"__type":"Pointer","className":"CategoryCandidates","objectId":"HOBbNA690z"},"createdAt":"2015-09-04T15:49:09.216Z","objectId":"RlmvJjG04t","updatedAt":"2015-09-04T15:49:23.549Z","userID":{"__type":"Pointer","className":"_User","objectId":"7YfU2ETvb3"}}}
Result: TypeError: Cannot read property 'objectID' of undefined
at main.js:6:53
The Parse documentation (https://parse.com/docs/js/guide#cloud-code-aftersave-triggers) has an example, but it's unclear to me what the lowercase "post" is referring to in their data schema. I'm also not well-versed in JS so might be making a rookie mistake there.
Thanks in advance for any suggestions or advice!
It can definitely be a bit of a head-scratcher to debug cloud code but you were nearly there. You want to access the objectId of the "CategoryCandidates" class pointer, which you are currently using request.object.get("CategoryCandidates").objectID to do.
The problem is, when you look at the log for the input to your afterSave, the name of the pointer is "candidateID", not "CategoryCandidates".
Try using request.object.get("candidateID").objectID
Cheers,
Russell
I am trying to find all documents and publish at most 5 from the results.
Following this section of the MongoDB doc, I am trying to do this:
Meteor.publish('teams', function () {
return Teams.find().limit(5);
});
Yet, in the server console, I get an exception:
Exception from sub teams id Pm6jKL8Sv3FSDSTfM TypeError: Object [object Object] has no method 'limit'
The following works fine:
Meteor.publish('teams', function () {
return Teams.find({}, {limit:5});
});
Why does the second way work, rather than the first? And where can I find documentation for it?
Meteor's collection API is somewhat different from that of the mongo API. find takes up to two parameters: a selector object, and an options object. options allows you to specify such things as sort, skip, limit and fields, in addition to the meteor-specific reactive and transform.
I'm new to Meteor. I've been stuck on this problem for a while. I can successfully adds items to a collection and look at them fully in the console. However, I cannot access all of the read operations in my .js file.
That is, I can use .find() and .findOne() with empty parameters. But when I try to add .sort or an argument I get an error telling me the object is undefined.
Autopublish is turned on, so I'm not sure what the problem is. These calls are being made directly in the client.
This returns something--
Template.showcards.events({
"click .play-card": function () {
alert(Rounds.find());
}
})
And this returns nothing--
Template.showcards.events({
"click .play-card": function () {
alert(Rounds.find().sort({player1: -1}));
}
})
Sorry for the newbie question. Thanks in advance.
Meteor's collection API works a bit differently from the mongo shell's API, which is understandably confusing for new users. You'll need to do this:
Template.showcards.events({
'click .play-card': function() {
var sortedCards = Rounds.find({}, {sort: {player1: -1}}).fetch();
console.log(sortedCards);
}
});
See this for more details. Also note that logging a cursor (the result of a find) probably isn't what you want. If you want to see the contents of the documents, you need to fetch them.
Rounds.find().sort({player1: -1}) returns a cursor, so you will want to do this:
Rounds.find().sort({player1: -1}).fetch();
Note that this returns an Array of document objects. So you would do something more like this:
docs = Rounds.find().sort({player1: -1}).fetch();
alert(docs[0]);