How do relations work in MeteorJS/Mongodb? - mongodb

and am not sure where to find this in the docs. How can I add more objects to the User object?
For instance if I run
meteor add accounts
and I get a full user collection with a working user login/signup template. I would like to add a posts collection/object inside this users collection, so that users can only view there own posts.
So how can I add each post to the current users object?

You can add users to the Meteor.users collection by adding accounts-password package. Use Accounts.createUser() method to create new users.
Find the documentation here: https://docs.meteor.com/api/passwords.html#Accounts-createUser

Meteor.users is a handle to users collection in Meteor. You can use it just as any other collection AKA
Meteor.users.findOne(id)
or
Meteor.users.update(...)
And of course you can't add posts collection to user collection. These will be different collections.
Storing objects in MongoDB under users collection document is pretty straight forward:
Meteor.users.update(
{ _id: userId },
{ $set: { objectFieldName: { a: 1, b: 2 }}}
)
Or if you need to do it on user create you should user Accounts package hooks.

You are approaching it wrong. Use pub/subs to achieve this.
When you insert a post, have a field called userId or ownerId
//inside Meteor.methods() on server side
Posts.insert({
owner: Meteor.userId(),
//some other fields
});
Then in your publication, return only the Posts that the user owns
//publication on server side
//checks if the visitor is a user
//if user, returns that user's posts
Meteor.publish('posts', function() {
if (this.userId) {
return Posts.find({owner: this.userId})
}
});
Then subscribe to the publication. No parameters needed:
//client side
Meteor.subscribe('posts')

Related

Meteor reactively copy certain fields from user collection to custom userprofiles collection

On Meteor, I have installed konecty meteor-user-presence (link) package to enable user status for each users on my application. This package adds additional fields (status, statusConnection) on Meteor User collection. In my current application setup, I have a different collection called UserProfiles that is used to store additional information about each users. I used id from the user collection as an identifier for the UserProfiles collection, under the field owner.
Is there a way to reactively copy updates from the two fields (status & statusConnection) from the user collection, to the custom UserProfiles collection?
I am able to achieve this using another package from Atmospherejs called collection-hooks {matb33:collection-hooks}. I basically add this into my main.js on the server:
Meteor.users.after.update(function (userId, doc, fieldNames, modifier) {
UserProfiles.update({
owner : doc._id
}, {
$set: {
status : doc.status
}
}, {multi: true})
});
This package add a hook to collections. Every time the application fires update to Meteor.users collection, which is basically every time when the konecty meteor-user-presence changes the status & statusConnection fields in the user collection, the collection-hooks package hook on the update action and perform additional tasks. The package also has other useful hooks e.g. before.insert,before.update, before.remove,after.insert, after.update and after.remove.
The {multi: true} is needed to enable the behaviour to be applied to all users. I do not know whether this will have an impact on the app performance, i'm sure it has some impact especially when the app scales up with large userbase. You should apply this solution carefully.
Here's a good primer for you to start: A Look At Meteor Collection Hooks

Role based firestore rules

We need to verify the user's role inside the firebase rules. A user can have one of the following roles: SUPPORT, ADMIN, MODERATOR.
The User object contains a roles collection, so that we are able to put some meta data on the respective role:
User Object
I tried to use this collection inside my firestore rules but I did not yet succeeded:
function getUserRoles(userId) {
return get(/databases/$(database)/documents/users/$(userId)/roles);
}
function hasRole(userId, role) {
return getUserRoles(userId) in role;
}
Unfortunately I was not able to find something in the docs how I can check if the role list contains the requeted role as document ID.
get() is only able to fetch a single document, not an entire collection. So, what you're trying right now is just not possible. Also bear in mind that you can only get() up to 10 documents per request.
Consider rewriting hasRole like this in order to check if the user's roles collection contains a document with the named permission:
function hasRole(userId, role) {
return exists(/databases/$(database)/documents/users/$(userId)/roles/$(role))
}
This assumes role is the string name of the role, for example, "SUPPORT". You will have to call this function for each individual role you want to check.
If you need to check the contents of the document as well, you will have to get() it instead, and look at the fields of the document..

Mongo: Two collections with pagination (in single list in html)

Currently in our system we have two separate collections, of invites, and users. So we can send an invite to someone, and that invite will have some information attached to it and is stored in the invites collection. If the user registers his account information is stored in the users collection.
Not every user has to have an invite, and not every invite has to have a user. We check if a user has an invite (or visa versa) on the email address, which in those case is stored in both collections.
Originally in our dashboard we have had a user overview, in which there is a page where you can see the current users and paginate between them.
Now we want to have one single page (and single table) in which we can view both the invites and the users and paginate through them.
Lets say our data looks like this:
invites: [
{ _id: "5af42e75583c25300caf5e5b", email: "john#doe.com", name: "John" },
{ _id: "53fbd269bde85f02007023a1", email: "jane#doe.com", name: "Jane" },
...
]
users: [
{ _id: "53fe288be081540200733892", email: "john#doe.com", firstName: "John" },
{ _id: "53fd103de08154020073388d", email: "steve#doe.com", firstName: "Steve" },
...
]
Points to note.
Some users can be matched with an invite based on the email (but that is not required)
Some invites never register
The field names are not always exactly the same
Is it possible to make a paginated list of all emails and sort on them? So if there is an email that starts with an a in collection invites, that is picked before the email that starts with a b in collection users etc. And then use offset / limit to paginate through it.
Basically, I want to "merge" the two collections in something that would be akin to a MySQL view and be able to query on that as if the entire thing was one collection.
I'm preferably looking for a solution without changing the data structure in the collection (as a projected view or something, that is fine). But parts of the code already rely on the given structure. Which in light of this new requirement might not be the best approach.

How to related/associate to Mongo Collections in Meteor without using simple schema

I am working on a meteor project.
Step 1
I've added the accounts-password and the accounts-ui packages so in order to have a users collection and an authenticating system.
Step 2
I've created a Mongo collection 'Posts' of documents with the following fields: _id, title, description and createdOn(date).
Step 3
I've created another Mongo collection 'Comments' of documents with the following fields: _id, comment ,postedOn('date') and createdBy(Meteor.user()._id)
Step 4
I've added the iron router package and set some routing. You can view a blog list and go to single post detail page.
I want to give the possibility to the users who are logged in to post comments
on a single comment without using the aldeed simple-schema package.
Find below some snippets from my project:
Template.posts_list.helpers({
posts:function(){
return Posts.find({}, {sort: {createdOn: -1} });
}
})
Template.comments.helpers({
comments:function(){
return Comments.find({ ????? Ho can I associate comments to a single post? });
}
})
I am wondering how can I make the proper association between the 2 collections. I would like to show only those comments associated to the related post. As of now all the comments appear to every post without distinction. Any help? Thanks
You want to add a postId to your comments schema. Then, whenever you're submitting a comment, get the _id of the post in question and send it to your meteor method where you're inserting the comment. Something like this:
// In your template events:
'submitCommentForm': function( event, template ) {
var postId = this._id; // Make sure your post data context of this form is set in a #each or #with.
Meteor.call('addComment', event.target.comment, postId, ...) // Assuming your comment is in some sort of named input with comment as the name.
}

Ideas how to query two collections in mongodb

I have collection friends
- userId: user id
- Friends: array of user ids
And users
- _id: userId
- Last Login
- Other User info fields
Last login field is updated every 5 minutes if user is browsing my website.
Right now I have logic where I get user ids from friends from friend collection, then query user collection with that ids to get user info.
ADDED: In addition in future releases i would add that user will be able to add friends not only users but pets from other collection so friend embedded array will look like {UserId, PetId}
But for next release I would like to add new functionality where I would show friends sorted by last login.
Solutions which I think would work
Map reduce on select -Easy to implement but would probably have problems with performance
Map reduce on update - in this case i would probably use property "out" to write new collection on each update, so then i will have new collection Friend.reduced with all info i need, and then i can easy query it by indexes
Add new property Last Update to Friends list collection so it will look like {FriendId, LastUpdate} logic would be easy to implement on Business level.
What other options to solve my issue?
And simple query like below won't work?
var someId = ObjectId("52758653cbd6ca816ca0ee1b")
var friends = db.friends.findOne({"userId": someId}, {"_id": 0, "friends": 1}).friends
db.users.find(
{_id: {$in: friends }}
).sort({lastLogin: -1})