Meteor publish-composite and nested collection - javascript

I am trying to build an app that has a many to many relationship in Meteor. There will be jobs, clients and users collections. Clients can have multiple jobs, and most importantly multiple users can work on the same job.
I have the jobs collection set up as follows in my fixtures file:
Jobs.insert({
jobNum: 'Somejob',
clientId: 'XXXXXXXX',
clientName: 'Some Client',
rate: XX,
userNames: [
{userId: user1._id},
{userId: user2._id}
],
active: true
});
I am publishing according to the readme for publish-composite, but I cannot get the users to publish to the client. Here is the publication code:
Meteor.publishComposite('jobsActive', {
find: function() {
// Find all active jobs any client
return Jobs.find({active: true});
},
children: [
{
find: function (job) {
// Return a client associated with the job
return Clients.find({_id: job.clientId});
}
},
{
find: function (job) {
// Return all users associated with the job
// This is where the problem is
return Meteor.users.find({_id: job.userNames.userId});
}
}
]
});
I can't figure out how to correctly find over an array. I tried a number of things and nothing worked. Is this possible? Or do I need to go about this in another way? I've thought about referencing jobs in the users collection, but there will be far more jobs than users, so it seems to make more sense like this.
BTW, I did subscribe to 'jobsActive' as well. The other two collections are coming over to the client side fine; I just can't get the users collection to publish.
Thanks for any help and ideas.

job.userNames.userId doesn't exist in your collection. job.userNames is an array of objects which have the key userId.
Try something like _.map( job.userNames, function( users ){ return users.userId } ).
Your code will be:
Meteor.publishComposite('jobsActive', {
find: function() {
return Jobs.find({active: true});
},
children: [
{
find: function (job) {
return Clients.find({_id: job.clientId});
}
},
{
find: function (job) {
return Meteor.users.find({ _id: { $in: _.map( job.userNames, function( users ) { return users.userId } ) } });
}
}
]
});

I think you don't need publish-composite at all, try this code snippet. It works for me!
Meteor.publish('jobsActive', function () {
return Events.find(
{
$or: [
// { public: { $eq: true } },
{ active: true },
{ userNames: this.userId}
],
},
{
sort: {createdAt: -1}
}
);
});

Related

Unable to remove item from array using Mongoose / UpdateOne

I have a Node.js application in which I am trying to remove an object from an array when an API endpoint is hit. I so far have been unable to get it to update/remove the object. Currently, the below query returns with no error but upon checking into my DB I am still seeing it. Below is my query and basic response (I will be adding more but that is outside the scope of this question). I have also included a sample of my data model.
In the below data model I am trying to remove the whole object from the foo array as it is no longer needed.
Code
const ID = req.params.id
await FooBar.updateOne({foo: {$elemMatch: {v_code: ID}}}, { $pull: {v_code: ID}}, (err) => {
if(err) return res.json({success: false, err})
return res.json({success: true, id: ID})
})
Data model
{
bar: [
{
foo: [
{
v_code: <>
_id: <>
}
]
}
]
}
I'm sure this has been asked for in other questions but none specific to my data model. I've tried piecing together multiple SO posts and that is how I got the $elemmatch and the $pull portions of my query and so far I've had zero luck
give the following command a try:
db.collection.updateOne(
{
"bar.foo.v_code": ID
},
{
$pull: { bar: { foo: { $elemMatch: { v_code: ID } } } }
}
)
https://mongoplayground.net/p/iqJki-mnHSJ

findByIdAndUpdate updating wrong sub-objects when using $set

To clarify, I'm trying to build a feature to let my users manage the notifications and emails they receive.
In order to do that, I decided to implement an object with several objects within itself.
Everything seems to make sense in my head but I'm here because I found a problem and I can not solve it by myself.
Here is the problem:
I have two endpoints and two function, each endpoint calls their respective function. Everytime I make a call to any of the two endpoints, said call updates not only the data on its endpoint but in the other endpoint as well, do I explain myself?
Let's put it this way, this is endpoint A {{URL}}/api/v1/auth/updateemailnotifications and this ednpoint B {{URL}}/api/v1/auth/updatenotifications. No matter which one is called, it updates the other's endpoint data as well.
ENDPOINT A:
const user = await User.findByIdAndUpdate(
{
_id: req.user._id
},
{
$set: {
settings: {
notifications: {
comments: {
fromBlogNotification: req.body.fromBlogNotification,
fromPostNotification: req.body.fromPostNotification,
fromVideoNotification: req.body.fromVideoNotification,
fromMediaNotification: req.body.fromMediaNotification,
fromProducerNotification: req.body.fromProducerNotification,
fromJobNotification: req.body.fromJobNotification,
fromCommentNotification: req.body.fromCommentNotification
},
news: {
fromBlogNewsNotification: req.body.fromBlogNewsNotification,
fromProducerNewsNotification:
req.body.fromProducerNewsNotification,
fromUserNewsNotification: req.body.fromUserNewsNotification
}
}
}
}
},
{
new: true,
runValidators: true,
// setDefaultsOnInsert: true
}
);
ENDPOINT B:
const user = await User.findByIdAndUpdate(
{
_id: req.user._id
},
{
$set: {
settings: {
emails: {
comments: {
fromBlogComments: req.body.fromBlogComments,
fromPostComments: req.body.fromPostComments,
fromVideoComments: req.body.fromVideoComments,
fromMediaComments: req.body.fromMediaComments,
fromProducerComments: req.body.fromProducerComments,
fromJobComments: req.body.fromJobComments,
fromCommentComments: req.body.fromCommentComments
}
}
}
}
},
{
new: true,
runValidators: true,
// setDefaultsOnInsert: true
}
);
Hopefully you guys can help me solve this, thanks!.
In your code, you are replacing the whole settings with the new value. To update specific field in settings, you need to use dot notation:
const user = await User.findByIdAndUpdate(
{ _id: req.user._id },
{
$set: {
'settings.notifications': {
...
}
}
},...

Meteor js: The page taking too much time to query with mongodb if records are around 100000

I am working on meteor js, there will be huge data in mongodb database. For now it is around 50000 messages in database. I am providing the code that I am currently using. For some reason the application is taking too much time to render or load the data from database. Also one more thing, if I am doing any activity,e.g. just like the messages the app fetches the messages again from database.
Template.messages.helper({
linkMessages() {
var ids = _.pluck(Meteor.user().subscription, '_id');
var messages = Messages.find({ $or: [{ feedId: { $exists: false }, link: { $exists: true } }, { feedId: { $in: ids }, link: { $exists: true } }] }, { sort: { timestamp: 1 }, limit: Session.get("linkMessageLimit") }).fetch();
return messages;
}
})
calling publication in oncreate method
Template.roomView.onCreated(function() {
const self = this;
Deps.autorun(function() {
Meteor.subscribe('messages', Session.get('currentRoom'), Session.get('textMessageLimit'), {
onReady() {
isReady.messages = true;
if (scroll.needScroll) {
scroll.needScroll = false;
if (scroll.previousMessage) {
Client.scrollToMessageText(scroll.previousMessage);
}
} else {
Meteor.setTimeout(function() {
Client.scrollChatToBottomMsg();
}, 1000)
}
}
});
});
});`
The publication function on server:
Meteor.publish('messages', function(roomId, limit) {
check(roomId, String);
check(limit, Match.Integer);
let query = { $or: [{ link: {$exists: false} }, { feedId: { $exists: false } }] };
const thresholdMessage = Messages.findOne(query, { skip: limit, sort: { timestamp: 1 } });
if (thresholdMessage && thresholdMessage.timestamp) {
query.timestamp = { $gt: thresholdMessage.timestamp };
}
return Messages.find(query, { sort: { timestamp: -1 } });
});
It is not a good practice to allow mini-mongodb to get populated with such a huge data. Though Meteor JS is good at this too, still it will take some amount of time taking into consideration the network traffic, bandwidth etc.
Irrespective of whether it is unlimited scroll or simple pagination I would suggest you to use pagination. I have already got it accepted and it works like charm, here is the answer and entire code for pagination.
My pagination solution is server specific, so it performs good. Collection publish is limited to the limit provided from subscription.
NOTE: There is yet no such proper full fledged solution for table with search and pagination and much more facility which makes it very flexible as per our need. I suggest to create your own.
MORE INSIGHTS:
https://www.quora.com/Does-Meteor-work-well-with-large-datasets
https://forums.meteor.com/t/very-big-data-collection-in-mongodb-how-to-fetch-in-meteor-js/6571/7
https://projectricochet.com/blog/top-10-meteor-performance-problems

How to load associations conditionaly in sequlize.js?

Post.findAndCountAll({
include: [{
model: models.like,
where: { userId: req.authSession.user.id }
]}
}).then( collection => {
onSucess(collection);
});
This will load posts if they have an associated like from the user. However what I want is loading all the user's post and loading the associated like if its exist. Can I archive this behaviour somehow with sequlize.js?
You just need to nest the where clause one level above.
Post.findAndCountAll({
where: { userId: req.authSession.user.id },
include: [{model: models.like}]
}).then( collection => {
onSucess(collection);
});
This will return all Posts that have userId === req.authSession.user.id and will include their likes ( if any ).
Edit according to the comment
If you want to have the Likes of the user you can just revert the query
Like.findAndCountAll({
where: { userId: req.authSession.user.id },
include: [ { model: models.post } ]
});

Mongoose update previously fetched collection

I would like to update a collection. Docs seem unclear on this.
I am wondering how to achieve the following:
Order.find({ _id: { $in: ids }}).exec(function(err, items, count) {
// Following gives error - same with save()
items.update({ status: 'processed'}, function(err, docs) {
});
});
I know how to batch save like this:
Model.update({ _id: id }, { $set: { size: 'large' }}, { multi: true }, callback);
But that requires setting my query again.
I've also tried:
Order.collection.update(items...
But that throws a max call stack error.
In mongoose, model.find(callback), return an Array of Document via callback. You can call save on a Document but not on an Array. So you can use for loop or forEach on the Array.
Order
.find({ _id: { $in: ids}})
.exec(function(err, items, count) {
items.forEach(function (it) {
it.save(function () {
console.log('you have saved ', it)
});
})
});

Categories