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