Reputation: 6257
I have a messaging app, that can display messages threads. In order not to bother with pagination, endless api calls and performance issues, I would like to automatically delete messages older than x days in an array in order to keep a small a amount of data.
How to do it? If it is not possible, how to automatically remove the oldest element from an array if it already has 50 elements while trying to push a new message? I could do it with native javascript, but maybe there is a cleaner way?
const mongoose = require("mongoose");
const conversationSchema = new mongoose.Schema(
{
name: { type: String, required: true, unique: true },
messages: [{ message: { type: String }, authorId: { type: String } }],
lastMessage: {
authorId: { type: String },
snippet: { type: String },
read: { type: Boolean },
},
},
{ timestamps: true }
);
conversationSchema.index({ name: 1 });
module.exports = mongoose.model("Conversation", conversationSchema);
Upvotes: 1
Views: 704
Reputation: 3390
The $slice operator allows $push
ing to an array and then limiting that array's length:
db.messageChannels.update(
{ _id: myMessageChannelId },
{
$push: {
messages: {
$each: [ "Hello world!" ],
$slice: -50
}
}
}
)
Similarly, on an update, you can use $pull
to remove any messages that match a criteria (in this case, the criteria would be being older than X days). This won't automatically expire these messages if nobody is using the channel (which you could automatically handle by deleting the whole channel if you track a lastMessageDate
on your whole channel using a TTL index).
db.messageChannels.updateOne(
{ _id: myMessageChannelId },
{ $pull: { messages: { sentAt: {$lte: expirationDate} }, $push: {messages: "Hello world!"} },
)
To expire all, you can run a query like the below on a cron:
db.messageChannels.update(
{ },
{ $pull: { messages: { sentAt: {$lte: expirationDate} } },
{ multi: true }
)
TTL indexes apply to the whole document so aren't workable, unless you group your messages by day
or something similar.
Upvotes: 1