Multiple updates queries in MongoDB - mongodb

couldn't find information about this, hope it's not a repeated question.
I would like to update multiple documents in MongoDB, but using specific queries and update values for each one, for instance, I have this model:
user: {
name: String,
email: String
}
Lets say that I have 2 documents:
User_A: {
name: 'Charles Montoya',
email: 'charles#email.com'
}
User_B: {
name: 'Robbin Faz',
email: 'robbin#email.com'
}
Now, what I would like to do is something like this:
db.user.update([
{ name: 'Robbin Faz' }, { $set: { email: 'robbin#email2.com' }, { upsert: true } },
{ name: 'Charles Montoya' }, { $set: { email: 'charles#email2.com' }, { upsert: true} }
])
If something like this is not possible, which way do you recommend me to work with a list of updates?, or should I do a "for"?
Thank you for your help.

You can do a bulk update and or upset:
> var bulk = db.user.initializeUnorderedBulkOp();
> bulk.find( { name: 'Robbin Faz' } ).upsert().update( { $set: { email: 'robbin#email2.com' } });
> bulk.find( { name: 'Charles Montoya' } ).upsert().update( { $set:{ email: 'charles#email2.com' } });
> bulk.execute();

Related

mongodb aggregation where document field is less than another field

Using mongoose, I'm trying to make a query that searches for tasks where timeSpent is greater than timeBilled.
Task schema:
const myTaskSchema = new Schema({
date: { type: Date, default: Date.now },
timeSpent: { type: Number },
timeBilled: { type: Number }
})
The query I've tried:
myTaskSchema.aggregate([
{
$match: {
timeSpent: { $gt: '$timeBilled' }
}
}
])
.then(data => {
console.log(data)
})
But I'm getting zero results (I know there should be results)
NOTE: Not every task has a timeSpent or timeBilled.field if that matters.
here is my dirty solution. It'd be nice if I didnt have to add a field but this gets me where I want to be.
myTaskSchema.aggregate([
{
$addFields: {
needToBill: { $gt: ['$timeSpent', '$timeBilled'] }
}
},
{
$match: {
needToBill: true
}
},
{
$project: {
timeSpent: 1,
timeBilled: 1
}
}
])

How to update multiple documents in mongodb using one query from an array of objects

I have the following array of objects...
[
{
_id: 'dfjkldsjfkldjas',
name: 'will'
},
{
_id: 'fdsfdakjdhfaskh',
name: 'bob'
},
{
_id: 'fdsfdasfdfewrfq',
name: 'tom'
}
]
Is there a way to search a mongodb collection for documents that match these _id's and then $set the name in the document all in one query? Maybe using updateMany?
You can use a bulkWrite to achieve this. First map your array and transform the data like so:
const data = [
{
_id: 'dfjkldsjfkldjas',
name: 'will'
},
{
_id: 'fdsfdakjdhfaskh',
name: 'bob'
},
{
_id: 'fdsfdasfdfewrfq',
name: 'tom'
}
]
const bulkData = data.map(item => (
{
updateOne: {
filter: { _id: item._id },
update: { $set: { name: item.name }}
}
})
);
Then you use the method bulkWrite to save the multiple data.
db.yourCollection.bulkWrite(bulkData);
You also don't have to use the same DB operation for every entry, you can use different ones on the same bulk like deleteOne, replaceOne, insertOne, etc.
You can check more here: https://docs.mongodb.com/manual/reference/method/db.collection.bulkWrite/
Try this for updating bulk data
const data = [
{
_id: 'dfjkldsjfkldjas',
name: 'will'
},
{
_id: 'fdsfdakjdhfaskh',
name: 'bob'
},
{
_id: 'fdsfdasfdfewrfq',
name: 'tom'
}
]
const bulkData = data.map(item => (
{
updateOne: {
filter: { _id: item._id },
update: { $set: { name: item.name } },
upsert: true
}
})
);
await db1.bulkWrite(bulkData, { ordered: false, upsert: true });

In Mongo - how to remove from a nested array with a specific id

This is my mongo collection
const cl = [{
id: '601ad0d7afe0642f781f7794',
history: [{
_id: '601ad0d7afe0642f781f7795'
}, {
_id: '601ad0d7afe0642f781f7796'
}]
}];
I want to remove the item in history with id: '601ad0d7afe0642f781f7795'
This method is not removing the item.
cl.updateOne(
{ 'history._id': '601ad0d7afe0642f781f7795' },
{
$pull: {
history: {
_id: '601ad0d7afe0642f781f7795'
}
}
}
);
Have also tried but also isn't removing the item.
cl.updateOne(
{ 'history._id': '601ad0d7afe0642f781f7795' },
{
$pull: {
history: {
_id: {
'$in': ['601ad0d7afe0642f781f7795']
}
}
}
}
);
Can anyone advise what I'm missing?

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 Find/Get Last Item w/ Parent Name and Object Array Value

Schema({
name: String,
items: [{
body: String,
active: Boolean,
_id: mongoose.Schema.Types.ObjectId,
added: { type: Date, default: Date.now }
}],
date: { type: Date, default: Date.now }
});
I want to get the last item in 'items' with a 'name' where 'items.active' is true.
Tried many different configurations.. this is basically what i want to do:
List.find({ name: LIST_NAME, 'items.active': true }, { items: { $slice: -1 } }, function(err, result){...do stuff w/ result.body...});
Appreciate any help, thx.
Using Aggregation was ultimately the solution:
List.aggregate(
{ $match: { name: req.params.list }},
{ $unwind: '$items' },
{ $match: { 'items.active': true }},
{ $sort: { 'items.added': -1 }},
{ $limit: 1 }, function (err, result) {
if(err) {
res.status(500);
res.send(err);
} else {
console.log(result);
res.send(result[0].items.body);
}
});