I’m building an app where users can be part of groups (multiple), and each group includes an invite system. An individual invite can be either pending | accepted | left
(the latter meaning the user left the group).
Two relevant Collections on the db side: Invites and Groups.
I’ve got two helpers that seem to be working fine, but I’m seeking to learn if I can be writing better Meteor code. My question is twofold:
- Am I hurting performance by using
.fetch()
in a helper? - Is there a better way to get the data from mongo by somehow using a query that joins the two Collections?
The second question is less important to me (for now) if the answer to the first question is no. Here’s code for two helpers:
acceptedInvites: function(){
var invites = Invites.find({used: true}, {sort: {createdAt: -1}}).fetch(); // are there invites?
if(invites.length){
var user = Meteor.user();
if(user){ // wait for reactive source
var group = user.profile.group;
var theGroup = Groups.findOne({_id: group}); // get the current user's group
// filter invites that have been accepted.
// accepted invites will mean the "members" property (type: array)
// on theGroup will *include* the uid assigned to the accepted invite
return theGroup && invites.filter(function(doc){
return theGroup.members.includes(doc.uid);
});
} else {
return false;
}
} else {
return false;
}
},
leftInvites: function(){
var invites = Invites.find({used: true}, {sort: {createdAt: -1}}).fetch(); // are there invites? (same as above)
if(invites.length){
var user = Meteor.user();
if(user){ // wait for reactive source
var group = user.profile.group;
var theGroup = Groups.findOne({_id: group});
// except here, we show the invites that were used
// but where the user is no longer in the "members" array
return theGroup && invites.filter(function(doc){
return !theGroup.members.includes(doc.uid);
});
} else {
return false;
}
} else {
return false;
}
}
And example data structure:
invites = [
{
"_id": "dRJEvcrGX4Aig8Z2g",
"acceptedAt": "2020-08-11T04:16:14.173Z",
"createdAt": "2020-08-11T04:14:51.314Z",
"invitee": "foo@bar.com",
"inviteeName": "wifey",
"message": "test",
"owner": "pjA3gsDEeRDr2wLyo",
"ownerName": "Mike",
"uid": "PiwmrTgetr3DceT8b",
"used": true
}
];
theGroup = {
"_id": "F74sRFo2b63wcnWWA",
"members": [
"pjA3gsDEeRDr2wLyo",
"PiwmrTgetr3DceT8b"
],
"startedBy": "pjA3gsDEeRDr2wLyo",
"createdAt": "2020-08-11T04:14:41.517Z",
"membersLeft": [
"PiwmrTgetr3DceT8b"
]
}
I understand using .fetch()
is less performant because it does not return a cursor that would allow Blaze to re-render only the bits that need re-rendering. But using .fetch()
is key here because I want to run a .filter()
on the data, which I can’t do with .find()
(at least insofar as I’ve researched).
Do the two helpers seem overly complicated and/or non-performant? Should I be doing a cross-Collection check instead (like joining tables in MySQL)? The motivation for asking is that while these may not be performance bottlenecks, at least right now, these helpers play their role in a larger ecosystem of helpers/templates in the app, so I’m wanting to be sure I’m doing things well for a smooth UX.
Thanks for any insight.