meteor - get value from collection serverside - meteor

I want to send an email from the current_user(client) to userY(a member) without exposing the emailaddress to the client. So all serverside.
I have the _id of userY (from the router param: email.toUser = Router.current().params._id;) and send it as a value to a method.
In the method function I want to do something like
var to = Meteor.users.find({ _id: email.toUser });
Now when I console.log(to) I get a huge _mongo object instead of the user profile (I expected to be able to log: to.profile.email) what's the best way to get the value from the email field?

What you are seeing is the cursor to the collection set.
To retrieve the records, you can use .fetch()
var to = Meteor.users.find({ _id: email.toUser }).fetch();
console.log(to[0].profile.email);
As you are looking up by ID, you are expecting only 1 result, so you could also use findOne() instead of find() this will return the first element directly.
var to = Meteor.users.findOne({ _id: email.toUser });
console.log(to.profile.email);
EDIT: I'd like to add that replacing { _id: email.toUser } by email.toUser should work. When using just the ID, there is no need to pass an object.

You should change find to findOne
Like this.
var to = Meteor.users.findOne({ _id: email.toUser });
find return the whole Mongo.Collection cursor

Related

Returning values from a subscription callback

I am trying to get the value of a field from a document returned via a subscription. The subscription is placed inside a helper function. I had a callback function within the subscription return this value and then I assigned the return value to a variable (see code). Finally, I had the helper return this value. However, the value returned is a subscription object (?) and I can't seem to get anything out of it.
Code:
Template.myTemplate.helpers({
'returnUser':function(){
var id = Session.get('currentUserId');
var xyz = Meteor.subscribe('subscriptionName',id,function(){
var user = accounts.find().fetch({_id: id})[0].username;
return user;
}
return xyz;
}
});
Any help will be much appreciated. :)
You have to load first your subscriptions when the template is created, this creates an instance of your data with Minimongo.
Template.myTemplate.onCreated(function () {
var self = this;
self.autorun(function() {
self.subscribe('subscriptionName',id);
});
});
Then in the helper, you can make a query to retrieve your data
Template.myTemplate.helpers({
'returnUser': function(){
var id = Session.get('currentUserId');
return accounts.findOne(id).username;
}
});

autoValue not working when you validate against mongodb collection fields

I am trying to set a value using autoValue based on already stored values
I am using meteor 1.3.4.1
This used to work in meteor 1.1.0.2
here is my code:
id: {
type: String,
label: "ID",
autoValue: function() {
var isFirstTime = this.field("profile.isFirstTime").value;
var isApproved = this.field("profile.changesApproved").value;
var value = this.field("profile.unapproved_id").value;
var userId = this.userId;
var user = Meteor.users.findOne({_id: userId});
if (user && user.profile && user.profile.id)
{
return user.profile.id;
}
}
}
I expect value of user.profile.id to be returned since user.profile.id has a value in the users collection but I get a value that is passed from input field. How do I get simple-schema to notice collection values as it used to on meteor 1.1.0.2
I think the confusing part here is the 'this' keyword. in the context of the autoValue function(), this may be the object itself, unless some other context is bound to it by SimpleSchema.
So would suggest you trace the code with debugger and check what is the value of this. if it is not what you think it is, check where it is defined

Modify data in Meteor.publish before sending down to client

I have the following use case:
I have a users table in MongoDB on the backend, which is a separate service than the frontend. I use DDP.connect() to connect to this backend service.
Each user has a set of "subjects"
Each subject in the users table is referenced by id, not name. There is a separate table called "subjects" that holds the subjects by id.
I want to publish the user down to the client, however I want the published user to be populated with the subjects first.
I tried the following, inspired by this blog post:
// in the backend service on port 3030
Meteor.publish('users', function(userId) {
var _this = this;
Meteor.users.find({
_id: userId
}).forEach(function(user) {
user.profile = populate(user.profile);
console.log(user);
_this.changed('users', userId, {
_id: userId,
profile: user.profile
});
});
_this.ready();
});
// in the client
var UserService = DDP.connect('http://localhost:3030');
var UserServiceProfile = UserService.subscribe('users', Meteor.userId());
console.log(UserServiceProfile);
This gives the following error on the backend:
Exception from sub users id akuWx5TqsrArFnQBZ Error: Could not find element with id XhQu77F5ChjcMTSPr to change.
So I tried changing _this.changed to _this.added. I don't get any errors, but the changes aren't showing up in the client minimongo, even though I can see that the populate function worked through the console.log(user) line.
I'm not sure how you'd fix your code, but you might not need to. It looks like you want the https://atmospherejs.com/maximum/server-transform package.
Add the server-transform package to your project, and replace your code with this (I'm going to assume you also have underscore added to your project, and the subjects collection in your database corresponds to a global variable called Subjects in your code.):
Meteor.publishTransformed('users', function(userId) {
return Meteor.users.find({
_id: userId
}).serverTransform({
'profile.subjects': function(doc) {
var subjects = [];
_(doc.profile.subjects).each(function(subjectId) {
subjects.push(Subjects.findOne(subjectId));
});
return subjects;
}
});
});

accessing Meteor.users.emails[0].address in Meteor.publish

I want to publish a collection to the owner which is accessed by this.userId (that part is working) and to those that the owner has invited. The only way I can do this is through the invited.email in my collection because the user being invited may not be a registered user yet.
Meteor.publish("meals", function () {
var current_user = Meteor.user();
return MealModel.find(
{$or: [{"invited.email": current_user.emails[0].address}, {owner: this.userId}]});
});
I don't want to publish the entire collection and query on the client side because I am afraid the collection could potentially get too big.
Any suggestions? Thanks.
Unfortunately, you can't use Meteor.user() inside of a publish function. Instead, you need to do a findOne with the userId. Give this a try:
Meteor.publish('meals', function() {
if (!this.userId)
return this.ready();
var user = Meteor.users.findOne(this.userId);
var email = user.emails[0].address;
return MealModel.find({$or: [{'invited.email': email}, {owner: this.userId}]});
});

Meteor collection.update permisions

Hi i dont understand why is this not working?
Notifications.update({'userId':Meteor.userId(), 'notifyUserId':notifyFriendId}, {$set: {read: 1}});
I have update allow method as well
Notifications = new Meteor.Collection('Notifications');
Notifications.allow({
update: function(userId, doc) {
return true;
}
});
Error appear:
Uncaught Error: Not permitted. Untrusted code may only update documents by ID. [403]
To update a collection you can only use the document's _id. So you need to query for it first
var docid = Notifications.findOne({'userId':Meteor.userId(), 'notifyUserId':notifyFriendId});
Notifications.update({_id:docid._id}, {$set: {read: 1}});
This is only for code that runs on the client. On the server you can run the code as you had it.
Just to update the above answer:
var documentIdentifiers = _.pluck(Documents.find({ param: 'yourParam'}, { fields: { _id: 1 }}).fetch(), '_id');
for (var i = 0; i < documentIdentifiers.length; i++)
Documents.update(documentIdentifiers[i], { $do: whatever });
This is what you do if you need to update multiple fields. The underscore pluck method, used in tandem with a field specifier, makes sure that data isn't being trucked around unnecessarily.
All my best,
Sam

Resources