How to update linked document in mongoose from parent? - node.js

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.

Related

How to log mongoDB query to terminal using Node JS

I am using the following code to add a schema model to my database...
db.on('error', console.error);
db.once('open', function() {
var Schema = new mongoose.Schema(
name: String,
_id: String
});
var User = mongoose.model('User', Schema);
new User({
name: "Help me!",
_id: "12345"
}).save(function(err, doc) {
if (err)
throw err;
else
console.log('save user successfully...');
console.log(User); //This is the problem
});
The code works fine, the schema gets loaded into the database, but the problem is I want to print the schema I just added on to the console window.
In the code above, I tried using console.log(User), but when I do so, all I get is a bunch of jargon that I cannot understand.
If I query the data using mongo terminal...
db.users.find()
I get...
{ "_id" : "12345", "name" : "Help me!"}
This is what I want to print to my console window when I run the code above, how can I do this?
To get back the document you just added, try using the create() method:
var Schema = new mongoose.Schema(
name: String,
_id: String
}),
User = mongoose.model('User', Schema),
obj = {
name: "Help me!",
_id: "12345"
};
User.create(obj, function(err, user) {
if (err)
throw err;
else
console.log('save user successfully...');
console.log(user); //This is the solution
});
You are console logging the User model and not the instance of the User which you created. Try console.log(doc); instead to see the new document you just created.

Update of multiple documents with mongoose fails

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);
});
}

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)
}
})
})

Mongoose - REST API - Schema With Query to different model

I'm trying to avoid DB Callback Queries.
Assuming that you have two schemas that looks like so :
1st) User Schema
username : {type: String, unique: true},
age : {type: Number}
2nd) Activity Schema
owner: [{type: Schema.Types.ObjectId, ref: 'User'}],
city: {type: String},
date: {type: Date}
So far so good.
Now lets say you have a route to /user/:id, what you would expect is to get the username and the age, but what if I would also like to return on that route the latest activity?
EDIT: Please note that latest activity isn't a value in the database. it's calculated automatically like activity.find({owner: ObjectId(id)}).sort({date: -1}).limit(1)
What is done right now:
User.findOne({username:req.params.username}).lean().exec(function(err,userDoc)
{
if(err) return errHandler(err);
Activity.findOne({owner:userDoc.username}).sort({date:-1}).exec(function(err,EventDoc){
if(err) return errHandler(err);
userDoc.latest_activity = EventDoc._id;
res.json(userDoc);
res.end();
})
})
The problem with the snippet above is that it is hard to maintain,
What if we want to add more to this API functionality? We would end in a callback of hell of queries unless we implement Q.
We tried to look at Virtual but the issue with that is that you can't
really query inside a mongoose Virtual, since it returns a
race-condition, and you are most likely not get that document on time.
We also tried to look at populate, but we couldn't make it since the documentation on populate is super poor.
QUESTION:
Is there anyway making this more modular?
Is there any way avoiding the DB Query Callback of Hell?
For example is this sort of thing possible?
User.findOne({username:req.params.username}).lean().populate(
{path:'Event',sort:{Date:-1}, limit(1)}
).exec(function(req,res))...
Thanks!
In this case, the best way to handle it would be to add a post save hook to your Activity schema to store the most recent _id in the latest_activity path of your User schema. That way you'd always have access to the id without having to do the extra query.
ActivitySchema.post('save', function(doc) {
UserSchema.findOne({username: doc.owner}).exec(function(err, user){
if (err)
console.log(err); //do something with the error
else if (user) {
user.latest_activity = doc._id;
user.save(function(err) {
if (err)
console.log(err); //do something with the error
});
}
});
});
Inspired by #BrianShambien's answer you could go with the post save, but instead of just storing the _id on the user you store a sub doc of only the last activity. Then when you grab that user it has the last activity right there.
User Model
username : {type: String, unique: true},
age : {type: Number},
last_activity: ActivitySchema
Then you do a post save hook on your ActivitySchema
ActivitySchema.post('save', function(doc) {
UserSchema.findOne({username: doc.owner}).exec(function(err, user){
if (err) errHandler(err);
user.last_activity = doc;
user.save(function(err) {
if (err) errHandler(err);
});
});
});
**********UPDATE************
This is to include the update to the user if they are not an owner, but a particpant of the the activity.
ActivitySchema.post('save', function(doc) {
findAndUpdateUser(doc.owner, doc);
if (doc.participants) {
for (var i in doc.participants) {
findAndUpdateUser(doc.participants[i], doc);
}
}
});
var findAndUpdateUser = function (username, doc) {
UserSchema.findOne({username: username}).exec(function (err, user) {
if (err) errHandler(err);
user.last_activity = doc;
user.save(function (err) {
if (err) errHandler(err);
});
});
});

Using mongoose to update a trip

I have been following the docs on how to update a trip using Node.js,mongoose,express, as well as a couple of stack overflow questions here and here.
Inside of my Controller I originally had a save, which was working, but I needed to switch it to an update. When I run the code, nothing breaks and the place is properly logged to the console as I would expect, which further indicates that the code is being run, but for some reason it isn't overwriting the item that has the same placeIdentifier.
What am I doing wrong that prevents this from updating?
My controller:
var place = {
identifier: placeIdentifier,
name: placeName,
location: Location,
travelStart: startDate,
travelEnd: endDate,
}
Place.findOneAndUpdate(
{identifier:placeIdentifier},
{ $set: place },
{upsert: true},
function() {
console.log(place)
console.log("place saved...")
}
);
Oh, I got it. Or rather, this person got it: Mongoose: Find, modify, save
User.findOne({username: oldUsername}, function (err, user) {
user.username = newUser.username;
user.password = newUser.password;
user.rights = newUser.rights;
user.save(function (err) {
if(err) {
console.error('ERROR!');
}
});
});

Resources