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().
Related
I work on meteor with mongodb. I am trying to get a collection from database. I can insert data without any problem in this collection from meteor, but when I try to find, it doesn't works.
My collection is 'first'.
Server side:
Meteor.publish('first', function(){
return first.find();
});
Client side:
var datacollab = first.find({"Mois":"Mars"});
console.log("collab: " + datacollab);
When I make this command line in mongo shell, it works fine.
I already try to change my request with findOne, or put .fetch at the end.
If you need your code to be in your Template.myTemplate.onRendered hook, then you have several options:
Use a Tracker.autorun that will be automatically re-executed when your DB query / cursor returns new data.
Use the onReady callback of the subscription (assuming you subscribe either when template is created or rendered). Your callback will be executed when the client has received a first full snapshot of the server publication.
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.
I have a collection of users with the following schema:
{
_id:ObjectId("123...."),
name:"user_name",
field1:"field1 value",
field2:"field2 value",
etc...
}
The users are looked up by the user.name, which must be unique. When a new user is added, I first perform a search and if no such user is found, I add the new user document to the collection. The operations of searching for the user and adding a new user, if not found, are not atomic, so it's possible, when multiple application servers are connect to the DB server, for two add_user requests to be received at the same time with the same user name, resulting in no such user being found for both add_user requests, which in turn results with two documents having the same "user.name". In fact this happened (due to a bug on the client) with just a single app server running NodeJS and using Async library.
I was thinking of using findAndModify, but that doesn't work, since I'm not simply updating a field (that exists or doesn't exist) of a document that already exists and can use upsert, but want to insert a new document only if the search criteria fails. I can't make the query to be not equal to "user.name", since it will find other users.
First of all, you should maintain a unique index on the name field of the users collection. This can be specified in the schema if you are using Mongoose or by using the statement:
collection.ensureIndex('name', {unique: true}, callback);
This will make sure that the name field remains unique and will solve the problem of concurrent requests as you have specified in your question. You do not require searching when this index is set.
From the looks of the syntax for handling mongodb related things in meteor it seems that you always need to know the collection's name to update, insert, remove or anything to the document.
What I am wondering is if it's possible to get the collection's name from the _id field of a document in meteor.
Meaning if you have a document with the _id equal to TNTco3bHzoSFMXKJT. Now knowing the _id of the document you want to find which collection the document is located in. Is this possible through meteor's implementation of mongodb or vanilla mongodb?
As taken from the official docs:
idGeneration String
The method of generating the _id fields of new documents in this collection. Possible values:
'STRING': random strings
'MONGO': random Meteor.Collection.ObjectID values
The default id generation technique is 'STRING'.
Your best option would be to insert records within a pseudo transaction where the second step is to take the id and collection name to feed it into a reference collection. Then, you can do your lookups from that.
It would be pretty costly, though to construct your find's but might be a pattern worthwhile exploring if you are building an app where your users will be creating arbitrary data patterns.
You could accomplish this by doing a findOne on all of the collections:
var collectionById = function(id) {
return _.find(_.keys(this), function(name) {
if (this[name] instanceof Meteor.Collection) {
if (this[name].findOne(id)) {
return true;
}
}
});
};
I tested this on both the client and the server and it seemed to work when run in the global context.
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.