Updating mongoose subSchema Object - mongodb

My Schema is like this
const subSchema = new Schema({ /*...*/ })
const mainSchema = new Schema({
//...,
foo:{
type:subSchema,
default:{}
}
})
const Model = model('Model', mainSchema)
If I am doing this the whole foo get replaced by req.body
Model.findByIdAndUpdate(_id,{ foo:req.body }, { new:true,runValidators:true })
But I want that the only fields present in req.body get replaced and the rest remain same

You can create an variable that contains fields to update from req.body first. Something like:
let update = Object.keys(req.body).reduce((acc, cur) => {
acc[`foo.${cur}`] = req.body[cur];
return acc;
}, {});
Model.findByIdAndUpdate(_id, update,...

You case use mongoose projection :
Model.findOneAndUpdate(
{ _id, 'foo._id': fooId },
{ $set: { 'foo.$': req.body } }
);
Mongoose params projection :
https://mongoosejs.com/docs/api.html#model_Model-find
MongoDB projection :
https://www.mongodb.com/docs/manual/reference/operator/projection/positional/

Related

Mongoose - which update function will also generate id for new property?

I have a subdocument inside a dosument and when I update my document, I want to generate ObjectId's. Both update and findByIdAndUpdate dont do that. I actually have to manually do that in my controller. Is there any way i can make it work?
const productSchema = new mongoose.Schema({
...
reports: [ReportSchema]
})
const ReportSchema = new mongoose.Schema({
...
info: String,
date: date
})
my controller:
updateProduct: async (req, res) => {
const product = await Product.update({id: id}, {
$push: {
report: {
info: info,
date: new Date(),
//_id: mongoose.Types.ObjectId() // only this works
},
}, $set: {isReport: true}}
)
res.status(200).send()
}
}

How to create dynamic query in mongoose for update. i want to update multiple data(Not all) with the help of Id

If I'm doing this, the field which I don't want to update is showing undefined. Any solution? (Like generating dynamic query or something)
exports.updateStudentById = async (req, res) => {
try {
const updateAllField = {
first_name: req.body.first_name,
last_name: req.body.last_name,
field_of_study: req.body.field_of_study,
age: req.body.age,
};
const data = await student_master.updateOne(
{ _id: req.body._id },
{ $set: updateAllField }
);
res.json({ message: "Student Data Updated", data: data });
} catch (error) {
throw new Error(error);
}
};
You can go for a dynamic query creation .Example
const requestBody = {
first_name: "John",
last_name: "Cena",
field_of_study: ""
}
const query={};
if(requestBody.first_name){
query["first_name"]=requestBody.first_name
}
if(requestBody.last_name){
query["last_name"]=requestBody.last_name
}
Check for the fields that are present in req.body and create a dynamic query
and when updating using mongoose use this
const data = await student_master.updateOne(
{ _id: req.body._id },
{ $set: query }
);
In this way only those fields would be updated which are present in your req.body

How to update document with subdocument, or create new one if none are found

I'm trying to create a new subdocument object in an array when a user calls a command OR update the existing document based on their id. However, everything I've tried either gives me errors or it overrides the existing subdocument with the current user which is not what I want.
enter image description here
Basically I want to add another object in the array ( "1": Object ) that is a second user tracking whether they've used the command or not.
I can't remember all variations on code, but the current code I'm using:
const query = {
_id: guild.id,
members : [{
_id: user.id
}]
}
const update = {
members: {
_id: user.id,
bot: user.bot,
commandUsed: true
}
}
const options = {upsert: true, new: true}
await mongo().then(async () => {
console.log('Updating to...in use')
try {
// Find the document
await commandUsageSchema.findOneAndUpdate(query, update, options, function(error, result) {
if (!error) {
// If the document doesn't exist
if (!result) {
// Create it
result = new userSchema;
}
// Save the document
result.save(function(error) {
if (!error) {
// Do something with the document
} else {
throw error;
}
})
}
})
is creating a duplicate key error which is frustrating. Here is the layout of my schemas:
const mongoose = require('mongoose')
const reqString =
{
type: String,
required: true
}
const userSchema = mongoose.Schema({
_id: reqString,
bot: Boolean,
commandUsed: Boolean
}, {unique: true})
const commandUseSchema = mongoose.Schema({
_id: reqString,
members: [userSchema]
})
module.exports = mongoose.model('command-usage-checker', commandUseSchema)
I'm using mongoose and mongoDB (of course) with javascript and DiscordJS.

Cast to ObjectId failed for value "comments" at path "_id" for model "post"

Comments is an array nested inside Post Schema. I want to update corresponding post by push a new comment to the comments array. But got the error: CastError: Cast to ObjectId failed for value "comments" at path "_id" for model "post"
Read related posts
Tried to use "mongoose.Types.ObjectId", didn't work
Mongoose version ^5.5.4
All the ID I am using here are valid
const PostSchema = new Schema({
...
comments: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'user',
},
body: {
type: String,
required: [true, 'Content required'],
},
}
],
...
});
PostRouter.put('/posts/comments', (req, res) => {
const { id } = req.query;
const userID = req.body.user;
const body = req.body.body;
const comment = {
user: userID,
body: body,
};
Posts
.update({ _id: id }, { $push: { comments: comment }})
.then(result => {
res.status(200).json(result.ok);
})
.catch(err => console.log(err));
});
I have a similar one: add a "friendID" to User Modal "friends" array. works as expected.
const senderID = req.query.sender;
const recipientID = req.query.recipient;
Users .update({ _id: recipientID }, { $push: { friends: senderID }})
.then(result => res.status(200).json(result.ok))
.catch(err => console.log(err));
but the "comment" I try to add here is an object instead of a valid ID string.
I think the problem is inside "Comments" array, because "comment.user" is ref from my "User" Schema. Don't know how to solve this nested question with cast error.
mongoose.Types.ObjectId is redundant if userID and _id are valid mongodb _id.
PostRouter.put('/posts/comments', (req, res) => {
const { id } = req.query;
const userID = req.body.user;
const body = req.body.body;
const comment = {
user: userID,
body: body,
};
Posts
.update({ _id: id }, { $push: { comments: comment }})
.then(result => {
res.status(200).json(result.ok);
})
.catch(err => console.log(err));
});

MongoDB not respecting $set { name: "a value" } in update query

I'm writing my own API in express to perform mongo update queries and I'm having trouble updating the "name" field specifically.
TagHandles.update(
{"uuid":req.params.id},
// {$set: { name : "piers" } },
{$set: { type : "works" } },
{upsert:true,safe:false},
function(err, data){
if (err){
console.log("ERROR");
console.log(err);
console.log(data);
} else {
console.log("SUCCESS");
console.log(err);
console.log(data);
}
res.send(err || data);
});
The TagHandles is a mongoose model with the following Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var TagHandle = new Schema({
type: String,
uuid: String,
handle: String
}, {
collection: 'tagHandles'
});
var TagHandles = mongoose.model('tagHandles', TagHandle);
Apparently mongoose prevents you from updating any fields not listed as part of the schema. So to correct, I added the line:
name: String
to the mongoose schema.