Mongoose: $unshift with findOneAndUpdate is not working properly - mongodb

I have this model:
const ProfileSchema = new Schema({
profileImageURLs: [
{
url: {
type: String,
},
current: {
type: Boolean,
},
date: {
type: Date,
default: Date.now,
},
},
],
});
And I have this function that updates the profileImageURLs field:
const updateProfileImageUrl = async (user_id) => {
const search_option = {
user: user_id,
};
const update_option = {
profileImageURLs: {
$unshift: {
url: `https://resources/profile_image`,
current: true,
},
},
};
const should_return_updated_profile = { new: true };
const updated_profile = await Profile.findOneAndUpdate(
search_option,
update_option,
should_return_updated_profile
);
console.log(
"🚀 ~ file: profileServices.js ~ line 1558 ~ updateProfileImageUrl ~ updated_profile",
updated_profile
);
};
The problem is the it is ignoring the values url and current in update_option and is only creating the _id and date fields:
profileImageURLs: [ { _id: 635ce632d633392b42c49094, date: 2022-10-29T08:37:06.012Z }]
And when I do a second update, instead of adding a new value to the beginning of the array, it creates a new array with the new values. So I have another array with a single object like that.
Any idea what's going on??

I used this instead and it works just fine:
const profile = await Profile.findOne(search_option);
profile.profileImageURLs.unshift({
url: profileImageURL,
current: true,
});
const updated_profile = await profile.save();

Related

MongoDB save and increment field

I need to save daily statistics with the number of message sent using WhatsApp using MongoDB, using mongoose / NodeJS.
According to document, using $inc, if the entry not exist a new is created.
But no one document is created when running this code.
I have this model
const mongoose = require('../database');
const StatWpSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
require: true,
},
date: {
type: Date,
require: true,
},
quantity: {
type: Number,
default: 0,
}
});
StatWpSchema.index({
userId: 1,
date: {
index: true,
sparse: true
},
});
const StatWp = mongoose.model('StatWp', StatWpSchema);
module.exports = StatWp;
And the code to save the statistics.
const statWp = require('../models/statWp');
let today = new Date().toISOString().slice(0, 10);
statWp.findOneAndUpdate(
{ userId: _userId, date: today },
{ $inc: { quantity: 1 } },
{ upsert: true },
function (err, response) { }
);

Delete object from inner schema in mongoose?

How do I delete object from inner schema in mongoose?
I try to delete comments from the Holiday Schema, this is the holiday schema:
const holidaySchema = new mongoose.Schema(
{
comments: [commentSchema],
},
)
const Holiday = mongoose.model("Holiday", holidaySchema);
export default Holiday;
and this is the comments schema:
const commentSchema = new mongoose.Schema(
{
action: { type: String },
time: { type: String },
name: { type: String },
image: { type: String },
content: { type: String },
rating: { type: Number },
},
{
timestamps: true,
}
);
I try to delete a specific comment from the holidaySchema in this way:
holidayRouter.delete(
"/:id/comments/:commentId",
isAuth,
expressAsyncHandler(async (req, res) => {
const holiday = await Holiday.updateOne(
{ _id: req.params.id },
{ $pull: { comments: { _id: req.params.commentId } } }
);
if(holiday){
console.log(holiday);
}
})
);
the console:
and this is not working, do you know what I am doing wrong or what should I do?
thank you
Mongoose converts the object into json, and we can customize that json which is returned.
commentSchema.methods.toJSON = function(){
const commentSchema = this.toObject()
delete commentSchema.name
delete commentSchema.rating
return commentSchema
}
New the JSON which is returned will not have name and rating.

How to update any amount of fields in a nested documen in Mongoose?

I need to update different fields of a nested array in Mongoose. Sometimes I will send runId and runStatus, some other times siteFetched and some other times siteInfo.
I have tried with the following code but the $set operator replaces the old fields.
The model:
campaignId: { type: String },
keywords: [{
keyword: { type: String },
serp: {
runId: { type: String },
runStatus: { type: String },
siteFetched: { type: Boolean },
sitesInfo: [{
title: { type: String },
url: { type: String },
description: { type: String },
}],
},
},
],
Here is the code to update
const campaign = await Campaign.findOneAndUpdate(
{ _id: campaignId, "keywords.keyword": keyword },
{
$set: { "keywords.$.apifySerp": {...serp }},
}
);
the value for serp varies like
const serp = {
runId: '1kLgbnvpADsDJyP1x',
runStatus: 'READY'
}
and
const serp = {
siteFetched: true
}
Here is the code that solved my problem.
const serp = {
siteFetched: true,
};
let update = Object.keys(serp).reduce((acc, cur) => {
acc[`keywords.$.apifySerp.${cur}`] = serp[cur];
return acc;
}, {});

make a path that increments the count

I'm trying to make a post request that will increment my schema using express and mongoose,
which is :
const ItemSchema = new Schema({
formName: String,
inputs: [
{
inputLabel: {
type: String,
required: true
},
inputType: {
type: String,
required: true,
enum: ['text', 'color', 'date', 'email', 'tel', 'number']
},
inputValue: {
type: String,
required: true
}
}
],
numOfSubs: { type: Number, default: 0 }
});
for my code purposes I want to make a route that will increase by 1 the numOfSubs everytime I use it,since there are a few listings, I have the ID so I need to search it, and I'm not sure how to write the path
router.post('/increase', (req, res) => {
"find and increase by 1 "
});
and I will use the fetch like so:
fetch('/api/items/increase', {
method: 'POST',
body: JSON.stringify({ _id }),//the ID I of the collection I want to increment
headers: {
'content-type': 'application/json'
}
});
try this using mongo $inc operator
router.post('/increase', (req, res, next) => {
const _id = req.body._id;
MyModel.findByIdAndUpdate(_id , { $inc: {numOfSubs: 1} }, { new: true }, (err,updateRes)=>{
if(err) return next(err);
return res.json({sucess: true});
});
});

MongoDB - Update Array with different types (discriminatorKey)

I have a document which can have an array of different sub documents.
Saving documents to the database work fine and the structure is exactly what I need.
My Problem is that I can not update values in the "sections" array (schema below)
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const logoSchema = require('./site-sections/logo');
var sectionSchema = new Schema(
{
show: { type: Boolean, default: true },
order: Number
},
{ discriminatorKey: 'type' }
);
const siteSchema = new Schema({
_user: { type: Schema.Types.ObjectId, ref: 'User' },
type: { type: String, required: true },
title: { type: String, default: '' },
name: { type: String, required: true },
password: { type: String, default: '' },
caching: { type: Number, default: 1 },
unique_id: { type: String, required: true },
sections: [sectionSchema]
});
const sectionArray = siteSchema.path('sections');
const headerSchema = new Schema({
image: { type: String, default: '' },
title: { type: String, default: '' },
sub_title: { type: String, default: '' },
show: { type: Boolean, default: true },
logo: logoSchema
});
sectionArray.discriminator('header', headerSchema);
const textSchema = new Schema({
text: String
});
sectionArray.discriminator('text', textSchema);
module.exports = mongoose.model('site', siteSchema);
My Update function:
req.body has the following value:
{ key: 'title',
value: 'Test',
unique_site_id: '_jxn7vw' }
const Site = require('../../models/site');
exports.update = async function(req, res, next) {
console.log(req.body);
if (req.body.unique_site_id) {
Site.update(
{
unique_id: req.body.unique_site_id,
_user: req.user.id,
'sections.type': 'header'
},
{
$set: {
['sections.$.' + req.body.key]: req.body.value
}
},
function(err, status) {
if (err) {
console.log(err);
return res.status(500).send();
}
console.log(status);
return res.status(200).send();
}
);
}
};
The console.log(status) always prints: { ok: 0, n: 0, nModified: 0 }.
How can I update the title value?
Discriminator keys cannot be updated. https://github.com/Automattic/mongoose/issues/3839
Ok. So the right order is:
convert mongoose document to object with toObject()
change discriminator, and change/delete other properties
convert back to mongoose document with hydrate()
save