This question already has answers here:
How can I update multiple documents in mongoose?
(7 answers)
Closed 7 years ago.
I have do do something like this (please forgive me about the stupidity of the example... :-):
var dateRef = new Date(1990, 1, 1);
Person
.where('dateOfBirth').gte(dateRef)
.update({ $set: { isYoung: true } }, function (err, count) {
})
;
I.e.: I'd like to $set to true field isYoung for every Person document whose date of birth (dateOfBirth) is later than a reference date.
My code is working for just one person, even if (currently) many documents do match the condition (all young people, here... :-).
Any clue?
P.S.: as a bonus, I'd like to set not-matching persons isYoung field to false, too, if possible...
You should use multi:true in update to update multiple documents like :
var dateRef = new Date(1990, 1, 1);
Person
.where('dateOfBirth').gte(dateRef)
.update({ $set: { isYoung: true } },{multi: true}, function (err, count) {
});
Related
This question already has answers here:
Update And Return Document In Mongodb
(7 answers)
Mongoose: findOneAndUpdate doesn't return updated document
(16 answers)
Closed 3 years ago.
Using Express and MongoDB, how can I update a document, then get that updated document?
The following code will find the profile document with the given user.id, then remove the experience with the given exp_id from the experience array. However, it returns the original profile (including the removed experience), not the updated one.
let profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $pull: { experience: { _id: req.params.exp_id } } },
{ returnNewDocument: true }
)
console.log(profile); // logs the original profile, still incl the removed experience
What do I need to change for it to return the updated profile?
Docs: https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndUpdate/
This question already has answers here:
MongoDB atomic "findOrCreate": findOne, insert if nonexistent, but do not update
(4 answers)
Closed 3 years ago.
Is there a way to omit adding/updating document if it was found in the collection without doing two requests to Mongo server? It would be perfect if this can be done in bulk, but I would appreciate to hear other options or workarounds.
What I'm looking for is sort of opposite of upsert option:
var bulk = MyCollection.initializeUnorderedBulkOp();
bulk.find({ x: val }).upsertOnlyIfNotFound({ x: newVal });
bulk.execute();
What you are looking for is $setOnInsert.
db.MyCollection.update(
{ x: val },
{
$setOnInsert: { x: "newVal" }
},
{ upsert: true }
)
From the documentation :
If an update operation with upsert: true results in an insert of a
document, then $setOnInsert assigns the specified values to the fields
in the document. If the update operation does not result in an insert,
$setOnInsert does nothing.
This question already has answers here:
MongoDB: How to update multiple documents with a single command?
(13 answers)
FindAndModify, return array of Objects
(1 answer)
Closed 5 years ago.
I am trying to use mongoose's findByIdAndUpdate method to pass in a list of object id's and updating them at once. However, I am getting a "Error: Can't use $set with ObjectId." error which I can't seem to associate with my code.
Here's my code.
return ComponentModel.findByIdAndUpdate({
_id: {
$in: input.subjectIds
},
$set: { location: input.newLocation }
}).then(res => res);
findByIdAndUpdate is for one document. For multiple documents you can use update with multi flag true.
return ComponentModel.update(
{_id: {$in: input.subjectIds}},
{$set: {location: input.newLocation}},
{"multi": true}
).then(res => res);
This question already has answers here:
How to Update Multiple Array Elements in mongodb
(16 answers)
Closed 5 years ago.
I'm starting with mongoDB and I want to update a nested array in my documents to add some initial value, but I can't find a way to do it with mong.
here is my document :
{
"_id":"cTZDL7WThChSvsvBT",
"name":"abc",
"players":[
{
"playerName":"Name1"
},
{
"playerName":"Name2"
}
]
}
What I want to do :
{
"_id":"cTZDL7WThChSvsvBT",
"name":"abc",
"players":[
{
"playerName":"Name1",
"NewField1":0,
"NewField2":0
},
{
"playerName":"Name2",
"NewField1":0,
"NewField2":0
}
]
}
Does anyone have a solution for this kind of situation?
This adds the new fields to the player array ...
db.collection.update({_id: 'cTZDL7WThChSvsvBT', players: {$exists: true}}, {$set: {'players.$.NewFieldOne': 0, 'players.$.NewFieldTwo': 0}})
... but since Mongo will only update the first element of an array which matches the query you are a bit stuffed. You can, of course, choose which array element to update by using the positional operator (as in my example) or by choosing a specific element (as the previous poster suggested) but until Mongo supports 'array updates' on all elements I think you're left with a solution such as: find the relevant documents and then update each one (i.e. a client side update solution).
I finally found a way by editing directly the document in JS like this :
db.doc.find({_id: myDocId}).forEach(function (channel) {
channel.players.forEach(function (player) {
player.newField1 = 0;
player.newField2 = 0;
});
db.doc.update({_id: myDocId}, channel);
});
considering you want to update an element which is an object also,
how about this?
db.collections.updateOne({_id: "cTZDL7WThChSvsvBT"}, {$set: {"players.0.NewField1": 0, "players.0.NewField2: 0}});
I have a mongo collection in which the documents have a field that is an array. I want to be able to publish everything in the documents except for the elements in the array that were created more than a day ago. I suspect the answer will be somewhat similar to this question.
Meteor publication: Hiding certain fields in an array document field?
Instead of limiting fields in the array, I just want to limit the elements in the array being published.
Thanks in advance for any responses!
EDIT
Here is an example document:
{
_id: 123456,
name: "Unit 1",
createdAt: (datetime object),
settings: *some stuff*,
packets: [
{
_id: 32412312,
temperature: 70,
createdAt: *datetime object from today*
},
{
_id: 32412312,
temperature: 70,
createdAt: *datetime from yesterday*
}
]
}
I want to get everything in this document except for the part of the array that was created more than 24 hours ago. I know I can accomplish this by moving the packets into their own collection and tying them together with keys as in a relational database but if what I am asking were possible, this would be simpler with less code.
You could do something like this in your publish method:
Meteor.publish("pubName", function() {
var collection = Collection.find().fetch(); //change this to return your data
_.each(collection, function(collectionItem) {
_.each(collectionItem.packets, function(packet, index) {
var deadline = Date.now() - 86400000 //should equal 24 hrs ago
if (packet.createdAt < deadline) {
collectionItem.packets.splice(index, 1);
}
}
}
return collection;
}
Though you might be better off storing the last 24 hours worth of packets as a separate array in your document. Would probably be less taxing on the server, not sure.
Also, code above is untested. Good luck.
you can use the $elemMatch projection
http://docs.mongodb.org/manual/reference/operator/projection/elemMatch/
So in your case, it would be
var today = new Date();
var yesterday = new Date(today);
yesterday.setDate(today.getDate() - 1);
collection.find({}, //find anything or specifc
{
fields: {
'packets': {
$elemMatch: {$gt : {'createdAt' : yesterday /* or some new Date() */}}
}
}
});
However, $elemMatch only returns the FIRST element matching your condition. To return more than 1 element, you need to use the aggregation framework, which will be more efficient than _.each or forEach, particularly if you have a large array to loop through.
collection.rawCollection().aggregate([
{
$match: {}
},
{
$redact: {
$cond: {
if : {$or: [{$gt: ["$createdAt",yesterday]},"$packets"]},
then: "$$DESCEND",
else: "$$PRUNE"
}
}
}], function (error, result ){
});
You specify the $match in a way similar to find({}). Then all the documents that match your conditions get pipped into the $redact which is specified by the $cond.
$redact scans the document from top level to bottom. At the top level, you have _id, name, createdAt, settings, packets; hence {$or: [***,"$packets"]}
The presence of $packets in the $or allows the $redact to scan the second level which contain the _id, temperature and createdAt; hence {$gt: ["$createdAt",yesterday]}
This is async, you can use Meteor.wrapAsync to wrap around the function.
Hope this help