Update of multiple documents with mongoose fails - node.js

I try to update multiple documents with mongoose (3.8.37), but no document is updated.
I've done all things, that I've learned from other questions (see below):
Use a callback function
Specify multi:true
My update statement:
Animal.where({ type: type}).update({deleted:1}, { multi: true, overwrite: true }, function (err,doc) {
console.log("updates: "+doc);
});
updates: 0
When I just count the documents, I'll get a result.
=> The query is correct
Animal.where({type: type}).count(function (err,doc) {
console.log("count: "+doc);
});
count: 299
When I omit the multi:true option, the first record is updated.
=> The update statement is correct, too
Animal.where({ type: type}).update({deleted:-1}, function (err,doc) {
console.log("updates: "+doc);
});
updates: 1
So where's the error?
There are several questions dealing with this topic. Unfortunately none of these solves my problem.
how can i update multiple documents in mongoose
Mongoose update multiple documents doesn't update anything
Mongoose: how to update *all* persons matching a condition?
** UPDATE
I've added a log callback and discovered that no query to the mongodb is executed as long as the options (multi:true) are specified.

I have setup small example which works as expected, first i called start() to create some users then update()
var mongoose = require('mongoose'); //v4.2.7
var userSchema = mongoose.Schema({
deleted: Number,
name: String
});
var User = mongoose.model('user', userSchema);
mongoose.connect('mongodb://127.0.0.1:27017/user');
//start();
function start(){
for (var i = 0; i < 5; i++) {
var user = new User({
deleted: 1,
name: i
});
user.save();
console.log('user ---> ', user);
};
User.find({}, function(err, docs){
console.log('found ---> ', err, docs);
});
}
update();
function update (){
User.update({deleted:1}, {$set: {deleted: 0}}, {multi:true}, function(err, numAffected){
console.log('updated ---> ', err, numAffected);
});
}
I'm not sure why update doesn't work with where(...)
function update (){
// this doesn't work
User.where({deleted:1}).update({$set: {deleted: 0}}, {multi:true}, function(err, numAffected){
console.log('updated ---> ', err, numAffected);
});
}

Related

Update element in Array of Mongoose schema

I am trying to update one element of snippets in my mongoose schema.
My Mongoose schema.
const Schema = new mongoose.Schema({
// ...
createdAt: Date,
snippets: {} // here I push ['string..', ['array of strings..']]
})
Here's a view of snippets in Compass.
Problem with the code below is that it completely erases other elements stored, other than that it works. Unable to specify that I want to update snippets[0], not entire thing..?
User.findOneAndUpdate({ username: req.session.user.username },
{ $set: { snippets: [snippet] } }, callback)
Tried using findOne andsave but it wouldn't update the db.
const snippet = [req.body.code, [req.body.tags]]
User.findOne({ username: req.session.user.username }, function (err, fetchedUser) {
if (err) console.log(err)
fetchedUser.snippets[req.params.id] = snippet // should be set to new snippet?
fetchedUser.save(function (err, updatedUser) {
if (err) console.log(err)
console.log('edited')
// ...
})
})
Any suggestions?
I thought I tried this earlier, but apparantly not.
Using fetchedUser.markModified('snippets') solved my issue with findOne/save not actually saving to DB.

Update data in MongoDB with Mongojs using findAndModify()

Yet another first-timer problem here. This gets data from a database and displays it in some text fields (that part is not shown in the code below) and after the user edits it the data should be updated in the database via the findAndModify() method and I think this is where the issue lies. There are no errors, it just doesn't do anything. EDIT The following error is received: MongoError: Either an update or remove=true must be specified
server.js
MongoClient.connect("mongodb://user:secretPassword#aws-us-east-1-portal.7.dblayer.com:10712,aws-us-east-1-portal.10.dblayer.com:10316/database", function(err, db) {
if (err) throw err;
var contactList = db.collection("contactList");
app.put('/contactList/:id', function(req, res) {
var id = req.params.id;
console.log("edited: " + req.body.name); //works up until here
contactList.findAndModify({
query: {_id: mongojs.ObjectId(id)},
update: {$set: {name: req.body.name, email: req.body.email, number: req.body.number}},
new: true
}, function (err, doc) {
res.json(doc);
})
});
controller.js
$scope.update = function() {
$http.put('/contactList/' + $scope.contact._id, $scope.contact).success(function(response) {
refresh();
})
};
If this were me I would first do a couple of things:
Before your call to findAndModify just do a simple find using your query. Make sure you can actually find the object using your query. If that works you know that the 'find' part of the findAndModify is probably ok.
Do some console logging inside the callback handler of the findAndModify call. As it stands you do not do anything if an err is returned from the findAndModify call. It is possible your call is returning an error that you are just ignoring and it may provide some additional insight into your problem.
I would try these two first and see if it helps.
Update:
Example using native:
collection.findAndModify(
{ field: 'some value' },
[],
{ $set: { field2: 'some new value' } },
{ new:true },
function(err, doc) {
//handle err and doc
});

How to update linked document in mongoose from parent?

I have a User model with a profile field pointing to profile model, like
UserSchema = new Schema({
name: {
type: String,
require: true,
unique: false,
},
profile:{type:Schema.Types.ObjectId, ref: 'Profile'}});
Now it is saving fine, but I want to update the User and Profile at the same time by sending an object like:
{
name : 'some name',
profile.location : 'some location'
}
my simple update code:
User.update({_id:userId},req.body,{},function(){
res.status(204).end();
});
It seems to only update the User's name, but not the linked Profile document's properties. What would be the best way to do this?
The Population (ref used in profile) is introduced into Mongoose,
Because there are no joins in MongoDB but sometimes we still want references to documents in other collections. Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s).
So it is not related to update operation for the reference document. Here are one sample codes to meet your requirement.
User.update({_id: userId},
{name: req.body.name}, function(err, u) {
if (err)
console.log(err);
else {
Profile.update({_id: u.profile},
{location: req.body.profile.locatio},
function(err) {
// error handling
})
}
});
If you are using DaftMonk's Angular Fullstack Generator, then just do this :
Install lodash npm install lodash
Include lodash in your JS file like this : var _ = require("lodash");
Finally do this :
var newUser = {};
newUser.name = "Some Name";
User.findById(userId, function(err, user){
if(err) console.log(err);
var updated = _.merge(user, newUser);
updated.save(function (err) {
if (err) console.log(err);
Profile.findById(user.profile._id, function(err, profile){
profile.location = "some location";
profile.save(function(err){
if(err) console.log(err);
console.log("Updated User and Profile");
});
});
});
});
Hope this helps.

Mongoose.js: isModified flag for attribute with default value

I have a model with a default generated value that doesn't change throughout the document lifetime except in one special case.
A document may get marked as deleted using doc.update({_id: doc._id, deleted_at: new Date()}, {overwrite: true})
In a very special case the document may be "revived" - looked up by it's id and being worked with again afterwards.
In a pre-save hook I need to perform some action (for example store a document in another collection) whenever the document is created or revived.
Consider following simplified code:
'use strict';
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var someSchema = mongoose.Schema({
immutable: {
type: String,
default: function () {
return 'SomeVeryRandomValue';
}
}
});
someSchema.pre('save', function (next) {
if (this.isNew || this.isModified('immutable')) {
console.log('Processing pre-save hook!');
}
next();
});
var SomeModel = mongoose.model('SomeModel', someSchema, 'test');
mongoose.connection.once('open', function (err) {
var testDoc = new SomeModel({});
console.log('New: %j', testDoc.toObject());
testDoc.save(function(err) {
console.log('Initial saved: %j', testDoc.toObject());
testDoc.update({_id: testDoc._id}, {overwrite: true}, function (err) {
// at this point using mongo console:
// > db.test.findOne()
// { "_id" : ObjectId("5617b028bf84f0a93687cf67") }
SomeModel.findById(testDoc.id, function(err, reloadedDoc) {
console.log('Reloaded: %j', reloadedDoc.toObject());
console.log('reloaded isModified(\'immutable\'): %j', reloadedDoc.isModified('immutable'));
reloadedDoc.save(function(err) {
console.log('Re-saved: %j', reloadedDoc);
mongoose.connection.close();
});
});
});
});
});
And the script runtime output:
$ node mongoose-modified-test.js
New: {"_id":"5617b64c5376737b46f6bb98","immutable":"SomeVeryRandomValue"}
Processing pre-save hook!
Initial saved: {"__v":0,"_id":"5617b64c5376737b46f6bb98","immutable":"SomeVeryRandomValue"}
Reloaded: {"_id":"5617b64c5376737b46f6bb98","immutable":"SomeVeryRandomValue"}
reloaded isModified('immutable'): false
Re-saved: {"_id":"5617b64c5376737b46f6bb98","immutable":"SomeVeryRandomValue"}
The immutable is not marked as modified and IMHO it should - original document had no value for that attribute.
A work-around solution is to remove the default value for immutable attribute and define pre-validate hook like this one:
someSchema.pre('validate', function (next) {
if (this.isNew || !this.immutable) {
this.immutable = 'SomeVeryRandomValue';
}
next();
});
This is not exactly what I need because the value won't be generated until I try to validate/save the document. The pre/post-init hooks are not executed on new SomeModel({}) so I can't use those.
Should I open an issue for mongoose.js?
this.$isDefault('immutable') can be used instead.
someSchema.pre('save', function (next) {
if (this.isNew || this.$isDefault('immutable')) {
console.log('Processing pre-save hook!');
}
next();
});
Output of the script with updated pre-save hook:
$ node --harmony mongoose-modified-test.js
New: {"_id":"56276f0c1a2f17ae7e0a03f7","immutable":"SomeVeryRandomValue"}
Processing pre-save hook!
Initial saved: {"__v":0,"_id":"56276f0c1a2f17ae7e0a03f7","immutable":"SomeVeryRandomValue"}
Reloaded: {"_id":"56276f0c1a2f17ae7e0a03f7","immutable":"SomeVeryRandomValue"}
Processing pre-save hook!
Re-saved: {"_id":"56276f0c1a2f17ae7e0a03f7","immutable":"SomeVeryRandomValue"}
Thanks to #vkarpov15 for clarification.

Mongoose findByIdAndUpdate not returning correct model

I have an issue I've not seen before with the Mongoose findByIdAndUpdate not returning the correct model in the callback.
Here's the code:
var id = args._id;
var updateObj = {updatedDate: Date.now()};
_.extend(updateObj, args);
Model.findByIdAndUpdate(id, updateObj, function(err, model) {
if (err) {
logger.error(modelString +':edit' + modelString +' - ' + err.message);
self.emit('item:failure', 'Failed to edit ' + modelString);
return;
}
self.emit('item:success', model);
});
The original document in the db looks like this:
{
_id: 1234
descriptors: Array[2],
name: 'Test Name 1'
}
The updateObj going in looks like this:
{
_id: 1234
descriptors: Array[2],
name: 'Test Name 2'
}
The model returned from the callback is identical to the original model, not the updatedObj.
If I query the db, it has been updated correctly. It's just not being returned from the database.
This feels like a 'stupid-user' error, but I can't see it. Any ideas greatly appreciated.
In Mongoose 4.0, the default value for the new option of findByIdAndUpdate (and findOneAndUpdate) has changed to false, which means returning the old doc (see #2262 of the release notes). So you need to explicitly set the option to true to get the new version of the doc, after the update is applied:
Model.findByIdAndUpdate(id, updateObj, {new: true}, function(err, model) {...
app.put("/vendor/:id",async (req,res)=>{
res.send(req.params)
await ModelName.findByIdAndUpdate(id, {type: change}, function(err, docs){
if(err){
conslole.log(err)
}else{
console.log(docs)
}
})
})
Example:
app.put("/vendor/:id",async (req,res)=>{
res.send(req.params)
const data = await userModel.findByIdAndUpdate(req.params.id, {isVendor: true},
function(err, docs){
if(err){
conslole.log(err)
}else{
console.log(docs)
}
})
})

Resources