In Mogoose i found my document with find, but using update not - node.js

I'm using nodejs and mongo (with mongooose) to build a simple aplication, but i have this little problem.
If i search my documento using a find method, i found the document (and yes, i can update in this), but if i use a update method, o cant find it. Why?
My controller method
var query = {
_id: ObjectId(req.params.runner_id)
};
Runner.find(query, function(e,o) {
console.log(o); //here i found
})
Runner.update(query, req.body, function (err, qtd) {
console.log(qtd); //here note
if (err) {
...
} else {
...
}
})
My Schema
module.exports = mongoose.model("Runner", new Schema({
cellphone: {
type: String,
require: "qual o telefone?",
unique: true,
validate: {
validator: function (v) {
var re = /^\d{11}$/;
return (v == null || v.trim().length < 1) || re.test(v);
},
message: "telefone inválido"
}
},
created_at: {
type: Date,
default: Date.now
},
advisors: [{
name: {
type: String,
require: "entre com o nome"
},
email: {
type: String,
require: "entre com o e-mail"
},
advisor: {
type: ObjectId,
require: "qual a assessoria?"
}
}]
}));
My output
with update -> { ok: 0, n: 0, nModified: 0 }
with find -> [ { _id: 5a0b99a9328fec0e4111ca52,
cellphone: '85999981114',
__v: 0,
advisors: [ [Object] ],
created_at: Wed Nov 15 2017 01:34:33 GMT+0000 (UTC) } ]

app.get('/', function(req, res){
var query = {
_id: ObjectId(req.params.id)
};
Runner.find(query, function(e,o) {
console.log(o); //here i found
})
}
app.put('/:id', function(req, res){
var Id=req.params.id;
Runner.findById(Id, function (err, qtd) {
console.log(qtd); //here qtd will found
if (err) {
...
} else {
...
}
}

Related

I want to pass array object inside array subdocument in mongoose

Here is my Schema
I am trying to add replies array inside answers array. If someone answers a question and if someone wants to reply on the given answer
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const questionSchema = new mongoose.Schema(
{
postedBy: {
type: ObjectId,
required: true,
ref: "User",
},
question: {
type: String,
required: true,
},
photo: {
data: String,
required: false,
},
answers: [
{
userId: { type: ObjectId, ref: "User" },
answerType: {
data: String,
required: false,
},
answer: String,
replies: [
{
userId: { type: ObjectId, ref: "User" },
reply: String,
replyType: {
data: String,
required: false,
},
},
],
},
],
questionType: {
data: String,
required: false,
},
createdAt: {
type: Date,
required: true,
default: Date.now,
},
},
{ timeStamps: true }
);
module.exports = mongoose.model("Question", questionSchema);
Here is my Controller method
exports.postReply = (req, res) => {
const reply = req.body.reply || "";
const userId = req.user._id || "";
const answerId = req.body.answerId || "";
Question.findByIdAndUpdate(
{ _id: answerId },
({ $push: { answers: { answer: { replies: { reply, userId } } } } },
{ new: true }),
(err, newReply) => {
if (err) {
res.status(400).json({
error: errorHandler(err),
});
} else {
res.json({
msg: "Reply posted successfully",
newReply,
});
}
}
);
};
I feel I am going wrong on the findOneAndUpdate method. I am getting no error on the console but newReply comes null. Any help will be appreciated.
I would suggest you using the $addToSet instead of the $push operator as you are adding a document to the array. (see: https://docs.mongodb.com/manual/reference/operator/update/addToSet/).
If you want to add more than one document to the array, refer also to the $each operator together with $addToSet.
So your coding can look similiar to this (note: the variable 'yourDocument' is the document you want to add):
Question.findByIdAndUpdate(
{ _id: answerId },
{ $addToSet: { answers: yourDocument } },
{ new: true },
(err, newReply) => {
if (err) {
res.status(400).json({
error: errorHandler(err),
});
} else {
res.json({
msg: "Reply posted successfully",
newReply,
});
}
}
);
};
The problem is clearly the parentesis around
({ $push: { answers: { answer: { replies: { reply, userId } } } } }, { new: true })
Doing this console.log( ({a:1}, {b:2}) ); will log {b: 2} which means you are doing this
Question.findByIdAndUpdate( { _id: answerId }, { new: true }, (err, newReply) => {
So remove the parentesis and you should be good
Question.findByIdAndUpdate(
{ _id: answerId },
{ $push: { answers: { answer: { replies: { reply, userId } } } } },
{ new: true },
(err, newReply) => {
if (err) {
res.status(400).json({
error: errorHandler(err),
});
} else {
res.json({
msg: "Reply posted successfully",
newReply,
});
}
}
);

Cast to ObjectId failed for value at path for model error

This is my Profile Schema:
const mongoose = require('mongoose');
const ProfileSchema = new mongoose.Schema({
user: {
// Special field type because
// it will be associated to different user
type: mongoose.Schema.Types.ObjectId,
ref: 'user',
},
company: {
type: String,
},
website: {
type: String,
},
location: {
type: String,
},
status: {
type: String,
required: true,
},
skills: {
type: [String],
required: true,
},
bio: {
type: String,
},
githubusername: {
type: String,
},
experience: [
{
title: {
type: String,
required: true,
},
company: {
type: String,
required: true,
},
location: {
type: String,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
education: [
{
school: {
type: String,
required: true,
},
degree: {
type: String,
required: true,
},
fieldofstudy: {
type: String,
required: true,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
social: {
youtube: {
type: String,
},
twitter: {
type: String,
},
facebook: {
type: String,
},
linkedin: {
type: String,
},
instagram: {
type: String,
},
},
date: {
type: Date,
default: Date.now,
},
});
module.exports = Profile = mongoose.model('profile', ProfileSchema);
This is my view api. It doesn't work. it only return Cast to ObjectId failed for value { 'experience._id': '5edcb6933c0bb75b3c90a263' } at path _id for model profile
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
const exp = await Profile.findById({
'experience._id': req.params.viewexp_id,
});
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
How can I fix this? I tried looking at the stackoverflow of the same errors. still it doesn't seem to work.
and this is what I am trying to hit
The problem is that you have to convert your string _id to mongoose object id using this function mongoose.Types.ObjectId and my suggestion is to use findOne function instead of findById,
var mongoose = require('mongoose');
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
let id = mongoose.Types.ObjectId(req.params.viewexp_id);
const exp = await Profile.findOne(
{ "experience._id": req.params.viewexp_id },
// This will show your sub record only and exclude parent _id
{ "experience.$": 1, "_id": 0 }
);
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
var mongoose = require('mongoose');
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
const exp = await Profile.findOne({
'experience._id': mongoose.Types.ObjectId(req.params.viewexp_id),
});
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
You are saving object id . but your param id is string. convert it in ObjectId. Please check my solution.
router.post(
"/",
[
auth,
[
check("status", "status is required").not().isEmpty(),
check("skills", "skills is required").not().isEmpty(),
],
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
company,
website,
location,
bio,
status,
githubuername,
skills,
youtube,
facebook,
twitter,
instagram,
linkedin,
} = req.body;
const profileFileds = {};
profileFileds.user = req.user.id;
if (company) profileFileds.company = company;
if (website) profileFileds.website = website;
if (location) profileFileds.location = location;
if (bio) profileFileds.bio = bio;
if (status) profileFileds.status = status;
if (githubuername) profileFileds.githubuername = githubuername;
if (skills) {
profileFileds.skills = skills.split(",").map((skill) => skill.trim());
}
//Build profile object
profileFileds.social = {};
if (youtube) profileFileds.social.youtube = youtube;
if (twitter) profileFileds.social.twitter = twitter;
if (facebook) profileFileds.social.facebook = facebook;
if (linkedin) profileFileds.social.linkedin = linkedin;
if (instagram) profileFileds.social.instagram = instagram;
try {
let profile = await Profile.findOne({ user: req.user.id });
if (profile) {
//update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFileds },
{ new: true }
);
return res.json(profile);
}
//Create profile
profile = new Profile(profileFileds);
await profile.save();
res.json(profile);
} catch (err) {
console.error(err.message);
res.status(500).send("server Error");
}
}
);

Failed to update single property by mongoose

Frist I have read and try the solution in the post of mongoose-and-partial-select-update.
However when I try to use the traditional style, query would work.
My schema:
var userSchema = mongoose.Schema({
local: {
email: {
type: String,
index: {
unique: true,
dropDups: true
}
},
password: String,
displayName: String,
avatar: {
type: String,
default: "./img/user.png"
},
role: {
type: String,
default: "student"
},
ask_history: [
{
question_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'questionAnswer'
},
favorite: Boolean,
ask_time: Date
}
],
interest: [String]
}
})
Working Update function:
User.findById(id, function(err, User) {
if (err) {
throw done(err);
}
if (!User) {
return;
}
User.local.role = "admin";
User.save(function(err, updatedUser) {
if (err) {
throw err
} else {
//good
}
})
});
However if I do this:
User.update({_id : id},
{$set{
local:{role:"admin"}
}
},function(...){...}
});
Code above will overwrite user into:
{
_id : "...",
local: {
role : "admin"
}
}
I read that $ will make the update only changing property, where I did wrong?
The positional operator $ works with array of subdocuments.
In your case you have a single sub-document, so the following should work:
User.update({_id : id},
{ $set
{
"local.role": "admin"
}
}, function(...){...}
});

mongoose findByIdAndUpdate instead of save

I'm trying to update the value of an element inside an array of my document.
The common way of update via save works as expected, but trying to use an static method, like findByIdAndUpdate doesn't work as expected.
Here bellow I paste the code I'm currently using:
var UserSchema = new mongoose.Schema({
nickname: { type: String, trim: true},
username: { type: String, trim: true },
notifications: [{
a: {
_id: { type: mongoose.Schema.Types.ObjectId, ref: 'x' },
x: { type: mongoose.Schema.Types.ObjectId, ref: 'y' }
},
b: {
_id: { type: mongoose.Schema.Types.ObjectId, ref: 'y' },
x: { type: mongoose.Schema.Types.ObjectId, ref: 'y' }
},
read: { type: Number, default: 0 }, // 0 - Unread, 1 - read
ts: { type: Date, default: Date.now }
}]
}, { timestamps: { createdAt: 'created_at' } });
// This works as expected
UserSchema.statics.rNSave = function (user_id, notification_id) {
var vm = this;
return new Promise(function (resolve, reject) {
vm.findById(user_id, function (err, data) {
if (err) {
reject(new Error(err));
} else {
var notifications = data.notifications, i = 0;
for (i; i < notifications.length; i += 1) {
if (data.notifications[i]._id.toString() === notification_id) {
data.notifications[i].read = 1;
data.save({ validateBeforeSave: false }, function (err, updatedData) {
if (err) {
reject(new Error(err));
} else {
resolve();
}
});
return;
}
}
return reject('Error');
}
});
});
};
// This one is not working
UserSchema.statics.rNStatic = function (user_id, notification_id) {
return this.findByIdAndUpdate({ _id: user_id, notifications: { $elemMatch: { _id: notification_id }}}, { $set: { 'notifications.$.read': 1 }}).exec();
};
Any help with this?
Thanks in advice.

Mongoose won't update sub-document

I've been banging my head against this for a few hours now and just can't seem to figure it out. I decided to use Mongo on a learning project to see how I like it. Mongoose came as the recommended way to use it, so I dove into that too. I have two schemas:
var PluginSchema = new Schema({
name: { type: String, required: true },
slug: { type: String },
description: { type: String },
created_date: { type: Date, default: Date.now },
active: { type: Boolean, default: true },
user: { type: Schema.Types.ObjectId, ref: 'User' },
versions: [PluginVersion.schema]
});
PluginSchema.methods.getLatestVersion = function(callback) {
if(this.versions.length > 0) {
this.versions.sort(function(a, b) {
if(semver.gt(a.version, b.version)) {
return 1;
} else if(semver.lt(a.version, b.version)) {
return -1;
} else {
return 0;
}
});
callback(this.versions[this.versions.length-1]);
} else {
callback(undefined);
}
};
and
var PluginVersionSchema = new Schema({
version: { type: String, required: true },
downloads: { type: Number, default: 0 },
size: { type: Number, required: true },
updatedChecks: { type: Number, default: 0 },
fileName: { type: String, required: true },
uploadedDate: { type: Date, default: Date.now }
});
The issue here is the 'versions' relationship. At some point I want to update a version of the Plugin. The thing I want to update is the updatedChecks field. Basically just updatedChecks += 1.
Plugin.findById(req.params.plugin_id)
.populate('user')
.populate('versions')
.exec(function(err, plugin) {
if(err) {
res.status(404);
res.send("Plugin not found.");
} else {
plugin.getLatestVersion(function(version) {
if(version !== undefined) {
pluginData = {
stuff: "that",
gets: "returned",
tothe: "user"
};
// This says 'Affected: 1'. As expected
PluginVersion.update({_id: version._id}, {
updatedChecks: version.updatedChecks + 1
}, function(err, affected) {
console.log("Affected: " + affected);
if(err) { res.send(err); }
res.status(200);
res.json(pluginData);
});
} else {
res.status(404);
res.send("No versions found for this plugin.");
}
});
}
});
So far, so good. However, when I try to access that version again via the Plugin schema, the updatedChecks value hasn't changed! I checked the _id value on the version I'm updating versus the version that gets pulled from the Plugin.versions field and they are they same. Do I need to remove the version from Plugin.versions and re-insert a new one with the updated value? I also tried just updating the value and calling save() but that didn't seem to work either.
I ended up getting this work by accessing the plugin version directly from the Plugin object.
var pluginIndex = false;
for(var i = 0; i < plugin.versions.length; i++) {
if(plugin.versions[i]._id === version._id) {
pluginIndex = i;
}
}
if(pluginIndex !== false) {
plugin.versions[pluginIndex].updatedChecks++;
plugin.versions[pluginIndex].markModified('updatedChecks');
plugin.versions[pluginIndex].save(function() {
plugin.markModified('versions');
plugin.save(function() {
res.status(200);
res.json(pluginData);
});
});
}
I also has a little help from: Mongoose save() not updating value in an array in database document
The problem here is, your updating query is written wrong. It must be
PluginVersion.update({
_id: version._id
}, {
$set: {
updatedChecks: version.updatedChecks + 1
}
}, function(...) {
...
});
or
PluginVersion.update({
_id: version._id
}, {
$inc: {
updatedChecks: 1
}
}, function(...) {
...
});
You can find more update operators here:
http://docs.mongodb.org/manual/reference/operator/update/

Resources