updating existing Mongo collection object in Meteor - mongodb

I saw the other answers like this, however I think mine is a little more specific.
I have Meteor.user() as Object {_id: "iymu2h9uysCiKFHvc", emails: Array[2], profile: Object, services: Object}
and I'm running a function to set the profile first name and last name here:
thisId = Meteor.userId();
Meteor.users.update({ _id: thisId }, { $set: {
profile: {
first_name: $('#firstName').val(),
last_name: $('#lastName').val()
}
}
});
I also, however, would like to, on a different event, add a a notifications object to the profile.
I tried :
thisId = Meteor.userId();
Meteor.users.update({ _id: thisId }, { $set: {
profile: {
notifications: {
rcptDwnldFile: Session.get('recpt-dwnld-file'),
rcptPaysInv: Session.get('recpt-pays-inv'),
invSentDue: Session.get('inv-sent-due'),
// the rest
}
}
}
});
but that overrides my first_name, last_name entries. I also tried $setOnInstert but i get a update failed: Access denied. Operator $setOnInsert not allowed in a restricted collection. but I thought that profile was writable by the user by default.

use this instead (more info link - see section Set Fields in Embedded Documents):
thisId = Meteor.userId();
Meteor.users.update({ _id: thisId }, { $set: {
'profile.first_name': $('#firstName').val(),
'profile.last_name': $('#lastName').val()
}
});
and
thisId = Meteor.userId();
Meteor.users.update({ _id: thisId }, { $set: {
'profile.notifications.rcptDwnldFile': Session.get('recpt-dwnld-file'),
'profile.notifications.rcptPaysInv': Session.get('recpt-pays-inv'),
'profile.notifications.invSentDue': Session.get('inv-sent-due'),
// the rest
}
});

Related

Update document array field if the new element not exist

var userSchema = mongoose.Schema({
username: { type: String},
email: String,
password: String,
tasks: [String]
});
I need to find the user document (by usename) and then to push a new task to the tasks array - if it does not already exist in the array.
I came to this solution:
user = await User.findOneAndUpdate(
{ username: username, 'tasks': { $ne: task} },
{ $push: { tasks: task } },{ 'upsert': false});
But how can I know to catch the reason the update didn't happened?
Is it because the username doesn't exist or is it because the task already exist?
$push will create duplicates in the task array. you need to use $addToSet operator:
db.collection.findOneAndUpdate(
{
username: 'test'
},
{
$addToSet: {
tasks: 'task'
}
},
{
returnNewDocument: true
})

Mongoose findOneAndUpdate with $addToSet pushes duplicate

I have a schema such as
listSchema = new Schema({
...,
arts: [
{
...,
art: { type: Schema.Types.ObjectId, ref: 'Art', required: true },
note: Number
}
]
})
My goal is to find this document, push an object but without duplicate
The object look like
var art = { art: req.body.art, note: req.body.note }
The code I tried to use is
List.findOneAndUpdate({ _id: listId, user: req.myUser._id },
{ $addToSet: { arts: art} },
(err, list) => {
if (err) {
console.error(err);
return res.status(400).send()
} else {
if (list) {
console.log(list)
return res.status(200).json(list)
} else {
return res.status(404).send()
}
}
})
And yet there are multiple entries with the same Art id in my Arts array.
Also, the documentation isn't clear at all on which method to use to update something. Is this the correct way ? Or should I retrieve and then modify my object and .save() it ?
Found a recent link that came from this
List.findOneAndUpdate({ _id: listId, user: req.user._id, 'arts.art': artId }, { $set: { 'arts.$[elem]': artEntry } }, { arrayFilters: [{ 'elem.art': mongoose.Types.ObjectId(artId) }] })
artworkEntry being my modifications/push.
But the more I'm using Mongoose, the more it feels they want you to use .save() and modify the entries yourself using direct modification.
This might cause some concurrency but they introduced recently a, option to use on the schema { optimisticConcurrency: true } which might solve this problem.

Get all the data of a field but populate only 10 of them in mongodb

I have User model with this friends schema:
friends: [{
type : Schema.Types.ObjectId,
ref: 'User'
}],
I tried this:
const user = await User.findById({ _id: userID })
.populate({ path: 'friends', options: { limit: 10 } })
this works.... but it actually loads and populate only 10 of the friends. I need to load all of them to display the count of the friends and populate 10 to display user avatar and such things...
How can I do this?
Also I have simimar problem with this schema:
comments: [{
user: {
type : Schema.Types.ObjectId,
ref: 'User'
},
comment: {
type: String
},
date: {
type: Date,
default: Date.now
}
}]
I tried this:
It populate all of the comments.user but how should I do this here because this:
const user = await User.findById({ _id: userID })
.populate({ path: 'comments.user', options: { limit: 10 } })
doesn't limit them....
You might be able to fix that by using aggregation + populate kind of like this (untested):
var result = User.aggregate([{
$match: { // filter by user id
_id: userID
}
}, {
$addFields: { // add count of friends
numberOfFriends: { $size: "$friends" }
}
}]);
and then
User.populate(result, { path: "friends", options: { limit: 10 } }, /* your callback */);

Mongoose pull ObjectId from array

i'm trying to do a pretty simple operation, pull an item from an array with Mongoose on a Mongo database like so:
User.update({ _id: fromUserId }, { $pull: { linkedUsers: [idToDelete] } });
fromUserId & idToDelete are both Objects Ids.
The schema for Users goes like this:
var UserSchema = new Schema({
groups: [],
linkedUsers: [],
name: { type: String, required: true, index: { unique: true } }
});
linkedUsers is an array that only receives Ids of other users.
I've tried this as well:
User.findOne({ _id: fromUserId }, function(err, user) {
user.linkedUsers.pull(idToDelete);
user.save();
});
But with no luck.
The second option seem to almost work when i console the lenghts of the array at different positions but after calling save and checking, the length is still at 36:
User.findOne({ _id: fromUserId }, function(err, user) {
console.log(user.linkedUsers.length); // returns 36
user.linkedUsers.pull(idToDelete);
console.log(user.linkedUsers.length); // returns 35
user.save();
});
So it looks like i'm close but still, no luck. Both Ids are sent via the frontend side of the app.
I'm running those versions:
"mongodb": "^2.2.29",
"mongoose": "^5.0.7",
Thanks in advance.
You need to explicitly define the types in your schema definition i.e.
groups: [{ type: Schema.Types.ObjectId, ref: 'Group' }],
linkedUsers: [{ type: Schema.Types.ObjectId, ref: 'User' }]
and then use either
User.findOneAndUpdate(
{ _id: fromUserId },
{ $pullAll: { linkedUsers: [idToDelete] } },
{ new: true },
function(err, data) {}
);
or
User.findByIdAndUpdate(fromUserId,
{ $pullAll: { linkedUsers: [idToDelete] } },
{ new: true },
function(err, data) {}
);
I had a similar issue. I wanted to delete an object from an array, using the default _id from mongo, but my query was wrong:
const update = { $pull: { cities: cityId }};
It should be:
const update = { $pull: { cities: {_id: cityId} }};

Mongodb - Get back object instead of array from find

db.users.find();
Will return me an array of users:
[{
_id: 123
name: bob
},{
_id: 456
name: tom
}]
I need to map users to another collection by the id, so I would like to get an object back from mongo where the keys are _id and values are the user doc.
i.e.
users = {
123: {_id: 123, name: bob},
456: {_id, 456, name:tom}
}
Then I can access users directly from that object without having to iterate an array to find specific users.
id = 123;
user = users[id];
You can't get an object like this one from mongodb, but it's quite easy to build it yourself:
db.users.find(function (err, docs) {
var users = {};
docs.forEach(function (doc) {
users[doc._id] = doc;
});
do_whatever_you_want_next(users);
});
Posting my solution in a more modern syntax:
const pushSubscriptions = await PushSubscription.find({ token: { $in: tokens } }).exec();
const userTokens = pushSubscriptions.reduce(
(result, ps) => {
result[ps.token] = ps;
return result;
},
{});