I can explain my issue using facebook as example,
take one news feed(one post), which has
post-content,images,videos
likes,comments,share
I'm saving the post_content,images,video(urls only) and like count in one collection called post
and all the likes in another collection called post_likes
now in the timeline I'm getting top 10 posts from the db
Posts.find({},{sort: {createdAt: -1}}.limit(10)
now, whenever user clicks on like, I'm calling a method which inserts the userid into the collection
post_likes.update({post_id:id},{$push:{userids: this.userId}})
post_likes object
{_id:"xxxx",post_id:"Id of the post",userids:["xxx","yyy",....]
I'm displaying in my template using
{{#each posts}}
.............
.........
........
.......
{{#if likes}}
//show dislike button
{{else}}
//show like button
{{/if}}
{{/each}}
Here my issue is
I want to know that current user is liked particular post or not.
I can't load all the liked_users to client side and check.
So I want to publish only one value from array to client
How to do this?
or Is there any alternatives to do this, any idea is welcome and appreaciated.
There are several alternatives:
Publish post_likes for each user:
Meteor.publish('user_post_likes', function() {
return post_likes.find({userids: this.userId});
});
Attach the post id to the user doc as well as vice versa:
post_likes.update({post_id:id},{$push:{userids: this.userId}}); // AND
Meteor.users.update({_id: this.userId}, {$push: {'profile.post_likes': id}});
Then you will have the likes already present in the user doc to which Meteor automatically subscribes. You can use something like matb33:collection-hooks to keep the two collections in sync if required.
Write a method to retrieve liked posts on demand:
Meteor.methods({
get_liked_posts: function() {
return post_likes.find({userids: this.userId});
}
});
The third is less "meteoric", but may be preferable if having lots of users subscribe to their own posts_likes subscriptions independently is hard work for the server. However, in that event, option 2 might be preferable instead.
Related
I'm adding custom data to Meteor user accounts for the first time. I've been able to add custom fields without difficulty and I know they're there because I can see them in Mongol. I am publishing via a global subscription so how do I then go about reading data from individual fields? It seems the syntax is very different from that when using publish/subscribe methods.
So, I have user accounts like this (as seen in Mongol):
"_id": "#################",
"profile": {
"name": "Test User"
},
"customfields": {
"customfield1": [
"A","B","C"
]
}
}
In server/main.js I have the following
Meteor.publish(null, function() {
return Meteor.users.find(this.userId, {fields:{customfields:1}});
});
This seems to be publishing fine. But what code do I use to render the cursor as data? I've been using variations on code like this in client/main.js and having no success:
var stuff = Meteor.users.find(this.userId).fetch();
console.log(stuff.customfield1);
Any help appreciated.
MyCollection.find() returns a cursor whereas MyCollection.findOne() returns an object, i.e. a single mongodb document.
A publication must return a cursor or array of cursors. You publication is fine.
You are basically trying to make the customfields key of the user object visible on the client. (The profile key is automatically published by Meteor).
On the client, where you are doing:
var stuff = Meteor.users.find(this.userId).fetch();
You can simply use:
var stuff = Meteor.user();
or
var stuff = Meteor.users.findOne(Meteor.userId());
Then stuff.customfields will contain what you're looking for.
The second form is way too verbose for me unless you're looking for a different user than the logged in user.
Note: this.userId on the client will not be the userId of the current user, it will be undefined. That only works on the server. That may actually be the root cause of your problem. In addition, your publications must be ready() for the data to be available. This isn't true immediately after login for example.
Since customfield1 is nested in customfields, did you try stuff.customfields.customfield1?
This is a Meteor/MongoDb question. In the code below, I am attempting to give all clients access to all users' Facebook names and Facebook profile Ids.
At the same time, I am attempting to give clients access to their own email as defined on their Facebook profiles.
Meteor.publish("users", function(){
return Meteor.users.find({}, {fields:
{'services.facebook.name': true,
'services.facebook.id': true}
})
});
Meteor.publish("mail", function () {
return Meteor.users.find({_id: this.userId},
{fields: {'services.facebook.email': 1}});
});
In the code below is how I have subscribed to the above publications.
Meteor.subscribe("users");
Meteor.subscribe("mail");
This should work as far as I am aware, yet when I attempt to make use of the user object, such as in the code below...
var user = Meteor.users.findOne({_id: Meteor.userId()});
console.log(user);
... I receive only the parts of the user object published as standard (profile.name & _id) and the parts of the user object published by the first meteor.publish function in the code above ("users"). The user's Facebook email is nowhere to be found. The code below demonstrates what I consistently keep receiving when I run the above findOne code.
{
_id: "3aNP7euRFGWhGEgq2",
profile: {name: "David Daish"},
services: {facebook: {name: "David Daish", ID: "1987779184781528"}}
}
As you can see, the Facebook email property is nowhere to be found. It's zilch, gone, not there. So there is my question:
How can I get services.facebook.email's value, and more importantly, how can I do it in a way that allows clients access to only their own services.facebook.email value?
Thank you very much in advance for your assistance. This has been confounding me for a couple days.
I got stuck at understanding Meteor Routes and data flow.
In the beginning it was simple blog app, with 1 collection named Posts.
Now I want to store history of changes, so I've created a second collection and named it History.
On every edit in Posts I'm adding state of post (author,content, etc ...) to History including the ID of edited post.
Question is how should I configure Iron Router to make it pass the current post id to posts/:_id/history from previous state (posts/:_id/) and get entries from History with this matching ID?
To pass the id from one view to the next, you can do it via template like so:
<a href="/posts/1/history>Post History</a>
or
<a href="/posts/{{_id}}/history>Post History</a>
or programmatically like so:
Router.go('postHistory', {_id: 1});
To get the history entries, you can resolve the data in iron router during the route request as so:
this.route('postHistory', {
path: '/posts/:_id/history',
data: function() {
return History.findOne({postId: this.params._id});
}
});
Without seeing your code it is hard to tell what you have tried already. But in order to help you understand Meteor routes perhaps you could take a look at these two links:
This introduction to routes with Iron Router
This link on more advanced routes
These should help you comprehend how to make two collections work together.
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.
I have created a simple, minimalistic diary app.
On the client, I use
Meteor.subscribe('entries', Meteor.userId());
to subscribe to the entries created by the user (stored in a mongodb collection). I pass the users ID to the publish function (on the server):
Meteor.publish('entries', function(userID) {
return Entries.find({userId: userID});
});
After login, Meteor.userId() isn't falsy anymore, because it's a reactive data source. However, the relevant data is not being published. I fixed that by auto-running the subscribe function:
Tracker.autorun(function() {
Meteor.subscribe('entries', Meteor.userId());
});
It works, but I feel it's a bad solution.
So here comes the question:
How should one publish user-relevant data in general? There must be a better way to do this, than passing the users ID to the publish-function. Also, isn't it insecure?
By the way, would love to hear some feedback on the app
You don't need to pass the userId from the subscription. Inside the publish function you can use this.userId to get the current user. You can also just return an empty array if the user is not logged in.
Meteor.publish("entries", function () {
if (!this.userId) return [];
return Entries.find({ userId: this.userId });
});