MongoDB save and increment field - mongodb

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

Related

Mongo How to use select to return multiple selected properties from document?

I am using findOneAndUpdate, where I want
to return updated document
i dont want to return the entire document but only the following:
one object out of an array + a virtual property in the document.
const notifications = {
to:
messages: [
{_id: "23452", title:"hello"}, {_id: "23452", title:"bye"}
]
...
}
so for example I would want to only return the object {_id: "23452", title:"bye"} AND unreadCount virtual field prop.
my code works so far as I am returning updated document and only the message I want, but I dont know how to return also the unreadCount prop.
schema:
const notificationSchema = new mongoose.Schema({
to: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
messages: [{
title: {
type: String,
required: true
},
isRead: {
type: Boolean,
default: false
},
createdAt: {
type: Date,
default: new Date()
}
}, ]
},
{timestamps: true, toObject: {virtuals: true}
});
notificationSchema.virtual('unreadCount').get(function() {
... return count;...
})
updateRead: async (userId, id) => {
const notification = await Notification.findOneAndUpdate({to: userId, 'messages._id': id}, {
$set: { "messages.$.isRead": true} },
{ select: {
messages: {
$elemMatch: {_id: id}
}
}, new: true});
}

Mongoose: $unshift with findOneAndUpdate is not working properly

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

Mongoose delete nested object on time expiration

I'm trying to find out the way to remove nested object in one collection once the document from another collection is expired
LocationsSchema.js
const mongoose = require('mongoose');
const locationsSchema = mongoose.Schema({
name: {
type: String,
required: [true, 'Please add a location name (string)']
},
confirmedBookings: [
{
startDate: {
type: Number
},
finishDate: {
type: Number
}
}]
}, {
timestamps: true
})
module.exports = mongoose.model('Locations', locationsSchema)
BookingsSchema.js
const mongoose = require('mongoose');
const Location = require('./locationModel');
const bookingSchema = mongoose.Schema({
startDate: {
type: Number,
required: [true, 'Please add a valid Date']
},
finishDate: {
type: Number,
> timestamp
required: [true, 'Please add a valid Date'],
index: true
},
location: {
type: mongoose.Schema.Types.ObjectId,
ref: Location
}
}, {
timestamps: true
})
bookingSchema.index({finishDate: 1}, {expireAfterSeconds: 0})
module.exports = mongoose.model('Booking', bookingSchema)
This is how I delete the object manually in
BookingsController.js
const deleteBookings = asyncHandler(async (req, res) => {
const booking = await Booking.findById(req.params.id);
if (!booking) {
res.status(400);
throw new Error('Booking not found');
}
await Location.findOneAndUpdate({_id: booking.location},
{$pull: {'confirmedBookings': {_id: req.params.id}}});
await booking.remove();
res.status(200).json({id: req.params.id});
})
But I also want to be able to delete the objects ones theirs finishDate are before the present time.
I tried to create an TTL index for that but it seems it doesn't work in the way I did it

Docs not deleted although expireAt passed

I have a database of documents in production that are not getting deleted although their expireAt suggest they should be. I can't reproduce the behavior locally - when I try the document does get deleted when they should.
Example of a document not getting deleted:
_id: "ca67081..."
accessToken: "de160..."
client: "WEB"
expireAt: 2021-09-28T07:59:10.459+00:00
keepSignedIn: false
createdAt: 2021-09-28T07:14:45.460+00:00
updatedAt: 2021-09-28T07:14:45.460+00:00
__v: 0
In my API I save the session as such:
const sessionId = await saveSession({
...(keepSignedIn ? { refreshToken } : {}),
accessToken,
client: client || constants.CLIENTS.WEB,
expireAt, //taken from a jwt-token
keepSignedIn,
});
And the model:
const mongoose = require('mongoose');
const { v4: uuid } = require('uuid');
const sessionSchema = mongoose.Schema(
{
_id: {
default: uuid,
type: String,
},
accessToken: {
required: true,
type: String,
},
client: {
required: true,
type: String,
},
expireAt: {
required: true,
type: Date,
},
keepSignedIn: {
required: true,
type: Boolean,
},
refreshToken: {
required() {
return this.keepSignedIn;
},
type: String,
},
},
{ timestamps: true },
);
sessionSchema.index({ expireAt: 1 }, { expireAfterSeconds: 0 });
module.exports = mongoose.model('Session', sessionSchema);
Versions:
db.version() = '5.0.3'
"mongoose": "6.0.7",
"connect-mongo": "4.5.0",
Any ideas on what could be the cause?

How to update a property in a nested array with mongoose

I want to push a Date object from my client into the nested array 'completed_dates' but I cannot figure out how to do so, or if I would need to change my schema in order for it to work.
{
_id: 606f1d67aa1d5734c494bf0a,
name: 'Courtney',
email: 'c#gmail.com',
password: '$2b$10$WQ22pIiwD8yDvRhdQ0olBe6JnnFqV2WOsC0cD/FkV4g7LPtUOpx1C',
__v: 35,
habits: [
{
_id: 6081d32580bfac579446eb81,
completed_dates: [],
name: 'first',
type: 'good',
days: 0,
checked: false
},
{
_id: 6081d32f80bfac579446eb82,
completed_dates: [],
name: 'seconds',
type: 'bad',
days: 0,
checked: false
},
]
}
and this is my schema
const habitSchema = new mongoose.Schema({
name: String,
category: String,
color: {
type: String,
},
date_added: {
type: String,
},
completed_dates: {
type: Array,
}
})
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
min: 6,
max: 255,
},
email: {
type: String,
required: true,
max: 255
},
password: {
type: String,
required: true,
max: 1024,
min: 8,
},
habits: [habitSchema]
})
Here is what I have tried...
I've tried using findOneAndUpdate, using the document id of the logged in user, and trying to manipulate the update object to drill into the nested array. I can access the habits list of the correct user... using this code, but for this new problem, I want to go one level further and push to the 'completed_dates' array of a specific habit (based on name or _id).
//this only adds a habit object to the habits array.
User.findByIdAndUpdate(req.user._id,
{ $pull: { habits: { _id: itemsToDelete } } },
{ new: true , useFindAndModify: false},
function (err, data) {
if (err) {
res.send(err)
} else {
res.send(data.habits)
}
}
)
I have tried building on this existing code by trying to filter down one more level. (this doesn't work.)
const { date, name} = req.body.update
User.findByIdAndUpdate(req.user._id,
{ $push: { 'habits.$[req.body.name].completed_dates': req.body.date} },
{safe: true, upsert: true, new : true, useFindAndModify: false},
function (err, data) {
if (err) {
res.send(err)
} else {
//data.update
res.send(data.habits)
}
}
)
If anyone can link or help me out, I would appreciate it. Thanks