How do you access attributes of an object queried from Mongo in Meteor - mongodb

I'm pretty new to mongo in the Meteor.js framework. Here, I've queried a MongoDB object using it's ID. I'm trying to access an attribute "mana" but it returns me undefined.
var skill = Skills.find({_id:Session.get("selected_skill")});
alert(skill);//This returns me "undefined"
Skills.update(Session.get("selected_skill"), {$inc: {mana: 1}});
Could you enlighten me on the requirements of accessing attributes in mongo for meteor? Thanks

find method returns a cursor, not object nor array. To access object, you need to either fetch it from the cursor
var skill = Skills.find(Session.get('selected_skill')).fetch()[0];
or get it directly with findOne:
var skill = Skills.findOne(Session.get('selected_skill'));
Then you may use it just as any other js object:
console.log(skill.mana);
skill._cache = {cooldown: true};
Keep in mind that on client-side, collection methods like find are non-blocking. They return whatever Meteor has in cache, not necessarily what is in the server-side db. That's why you should always use them in a reactive context, or ensure that all data has been fetched before execution (don't worry about the latter until you're fluent with Meteor, start with the first way).
Also, you need to keep in mind that because of this, findOne and find.fetch may return null / empty array, even when the corresponding element is in db (but hasn't been yet cached). If you don't take that into account in your reactive functions, you'll run into errors.
Template.article.slug = function() {
var article = Articles.findOne(current_article);
if(!article) return '';
return slugify(article.title);
};
If we didn't escape from the function with if(!article), the expression article.title would raise an error in the first computation, as article would be undefined (assuming it wasn't cached earlier).
When you want to update the database from client side, you can alter only one item by a time, and you must refer to the item by its _id. This is due to security reasons. Your line for this was ok:
Skills.update(Session.get('selected_skill'), {$inc: {mana: 1}});
alert() is a function that returns undefined no matter what you feed it.
alert(42); // -> undefined
Generally, it's far better to debug with console.log than with alert.

Related

Meteor JS : How to get latest set of data based on the date?

I have a requirement where my db has say some set of records with same timestamp (latest) and i want to get all of them at once, i don't want to get any other data which doesn't belong to that criteria, problem is i will not know the timestamp because it stored in db from outside world.
How do i get only the latest set of data in meteor ? i cant do findOne, as it will bring only 1 latest record, which is wrong in my case.
Meteor.publish("collection1", function() {
return Collection1.find({}, {sort:{dateTime: -1}});
});
I tried to do above code but it gets all the record and i think it just sort by desc.
Use the findOne() method to get the latest dateTime value that you can then use as the find() query:
// on the server
Meteor.publish("collection1", function() {
var latest = Collection1.findOne({}, {"sort":{"dateTime": -1}}).dateTime;
return Collection1.find({"dateTime": latest});
});
// on the client
Meteor.subscribe("collection1");
Collection1.find().fetch();
The above approach makes your Meteor app scalable client-side as the client only subscribes to the data that you only need. This is made possible because the return statement inside the Meteor.publish function can only return documents that have the latest dateTime value. This way, you'll avoid overloading the browser's memory no matter how big your server-side database is.

Meteor mongo get and set value

I am pretty new to Meteor and I'm just toying around to explore it at the moment.
I've got stuck with an issue trying to get and set a value in the mongo database, named Persons.
The MongoDB is named Persons and I've inserted two objects:
{name: "abcdef", coming: "false"}
If the user changes the state of a checkbox, that's attached to a name, a function is called that should find the value of the boolean coming.
What I think I got right so far, is that I can set the value like this?
var id = this._id;
Persons.update({_id: id}, {$set: {coming: true}});
But how can i get the value and make comparisons with it?
In meteor you use .find(selector).fetch() or .findOne(selector) on collections to get objects, where selector is a usual mongodb selector or just an id (string). After that you can pick out any fields using the usual . syntax of javascript.
Example:
var obj = Persons.findOne(id);
if (obj) { // the given id was found
console.log(obj.coming);
}

excecute function upon document insertion

I'm trying to find a way to achieve the following pseudo function on the server.The fields likesRecieved likesShown and likesMatch in exist in a document within the Posts collection.
I require this function to perform for every document in post collection by default. This is because Id like the function to do this...
1) find value(s) that exist in likesRecieved and likedShown fields.
2) insert these value(s) in likesMatch field.
3) remove values found in operation 1 from likesRecieved and likesShown
This is what I am essentially trying to do on the server...
likesRecieved: idA, idB, idE, idF, idL
likesShown: idE, idC, idF
..perform a function to result in the following...
likesRecieved: idA, idB, idL
likesShown: idC,
likesMatch: idE, idF
This is my code to find the ids in both arrays for one document only. The likeMatch helper returns the userIds that may exist in both 'likesRecieved' and 'likesShown' fields within a selected document in Posts collection. The resulting value(s) are then inserting into the likesMatch field.
likeMatch: function() {
var selectedPostId = Session.get('postId'); // _id of document in Post collection
var arrayOfLikeRecieved = Posts.find({_id: selectedPostId}, {fields: {LikesRecieved: 1}}).fetch();
var sumArrayRecieved = _.chain(arrayOfLikeRecieved).pluck('LikesRecieved').flatten().value();
var arrayOfLikeShown = Posts.find({_id: selectedPostId}, {fields: {LikesShown: 1}}).fetch();
var sumArrayShown = _.chain(arrayOfLikeShown).pluck('LikesShown').flatten().value();
var duplicates = _.intersection(sumArrayRecieved, sumArrayShown);
Meteor.call('insertDuplicateIntoMatchField', duplicates);
},
MongoDB doesn't have hooks like some other databases do, so there's no way to automatically have a function called when a document is inserted.
You have a couple of options, though. One way would be to have a hook in your application that runs just before inserting the document to run your function. This could be achieved in meteor by using a Collection.deny function.
If you would prefer to have the function be executed in mongodb, then you'll have to call the function manually. The problem is just how to know when the document was inserted or updated. Luckily, meteor allows you to observe changes to a cursor. You could use that to make a call out to the database and run a stored procedure (function) whenever a document gets updated.

Mongodb, get full object from a reference

Does exist anything permitting us to access a full object from a reference with Mongodb ?
For example, I have a User and a Type collection. A user has a Type, stored with a reference to the Type object.
Is it possible to access the full User object with the Type, without lazyloading it ?
Thanks for all
Yes; if you're happy making use of mongoose, then you can use its populate() function:
Populated paths are no longer set to their original _id , their value is replaced with the mongoose document returned from the database by performing a separate query before returning the results.
http://mongoosejs.com/docs/populate.html
So for your User, when performing a query to derive said user, something like this would set up the Type instance:
User.findOne({ username: 'Fred Bloggs' }).populate('type')
.exec(function (err, user) {
...
MongoDB does not do joins. It's not possible to get the information to embed the full Type object in the User document without more than one operation (I guess you have to "lazyload" it, in your terminology). The Mongoose populate() function just handles doing the extra queries and replacing the id with the document for you - it does multiple queries just like any other client doing the same operation would have to. You should think carefully about what types of queries you are doing to determine if it might be a good idea to denormalize the Type object into User documents.

Meteor allow deny functions?

In my application i am using a collection called Polls_Coll
here is my allow function
Polls_Coll.allow({
insert:function(){
return true;
},
update:function(userId, doc, fields, modifier){
return (doc.owner===userId);
},
remove:function(){
return true;
}
});
i inserted a document after log-in to my account
when i try to update that document values from client side
var option_data=Polls_Coll.findOne({_id:this._id}).option2[0].pd;
var u_name=Meteor.user().profile.name;
Polls_Coll.update({_id:this._id,"option2.pd":option_data},{$push:{"option2.$.ids":u_name}});
it is showing error that untrusted code may update using id only but it is working when i try to insert it from server side
Here is how i inserted document into collection
Polls_Coll.insert({question: quest,
option1:[{pd:op1,ids:[]}],
option2:[{pd:op2,ids:[]}],
option3:[{pd:op3,ids:[]}],
option4:[{pd:op4,ids:[]}]
});
why the values are not updating from client side.
From this section in the docs:
Untrusted code includes client-side code such as event handlers and a browser's JavaScript console.
Untrusted code can only modify a single document at once, specified by its _id.
So, I believe, the only selector allowed is an _id. You can achieve the same result with the $set operator with something like:
var poll = Polls_Coll.findOne({_id: this._id});
poll.option2[0].ids.push(Meteor.user().profile.name);
Polls_Coll.update({_id: this._id}, {$set: {option2: poll.option2}});
Meteor handles update() differenty for trusted code ( on the server ) than it does for untrusted code ( on the client ).
Untrusted code can only modify a single document at once, specified by its _id. - from http://docs.meteor.com/#update
Any other criteria inside of the update() selector would allow you to learn what is in the db object by trying multiple selectors, so the development group has eliminated this possibility. If you need to verify that other criteria are met before updating then check this with findOne().