Mongoose: create the same subdocument in multiple places - mongodb

I have a chat structure that holds both, all messages and last message in one parent document (chat). When the user sends a message, I need to update last_message and append the new message to messages array. Is it possible to do in a single update oparation so _id, created_at and updated_at will be the same in both sub-documents?
Here is my attempt that doesn't work:
const message = {
content: req.body.contentg,
sender: sender.toObject(),
};
const chat = await Chat.findOneAndUpdate({
_id: toObjectId(req.params.chat_id),
status: 'active',
}, {
last_message: message,
$push: { messages: message },
}, {
new: true,
});
Update: Added schemas (I'm using ts-mongoose)
export const MessageSenderSchema = createSchema({
last_name: Type.string(),
first_name: Type.string(),
phone: Type.string({ required: true }),
email: Type.string(),
status: Type.string({ enum: UserStatuses, required: true }),
}, {
skipVersioning: true,
});
export const ChatMessageSchema = createSchema({
content: Type.string({ required: true }),
status: Type.string({ enum: ChatMessageStatuses, default: 'new' }),
sender: Type.schema({ require: true }).of(MessageSenderSchema),
});
ChatMessageSchema.set('timestamps', { createdAt: 'created_at', updatedAt: 'updated_at' });
export const ChatSchema = createSchema({
__v: Type.number({ select: false }),
status: Type.string({ enum: ChatStatuses, default: 'active', required: true }),
members: Type.array().of({
$ref: Type.string(),
$id: Type.objectId(),
$db: Type.string({ required: false }),
}),
messages: Type.array().of(ChatMessageSchema),
last_message: Type.schema().of(ChatMessageSchema),
});

Related

How to populate object array in mongoose?

I wanted to populate 'item' in here and I'm getting the below error. It is an object array. This method worked for a normal array but gave an error for an object array. How to resolve it?
// Get the reserved list
const reservedDetails = await reserveInventory
.findOne({ memberID: id })
.select("itemsList")
.populate({
path: "item",
model: inventoryItem,
});
Error:
Cannot populate path `item` because it is not in your schema. Set the `strictPopulate` option to false to override.
reserveInventory Model:
const reserveInventorySchema = mongoose.Schema({
memberID: {
type: String,
ref: "member",
required: true,
},
itemsList: [
{
item: {
type: String,
ref: "inventoryItem",
},
quantity: {
type: Number,
},
},
],
});
module.exports = mongoose.model("reserveInventory", reserveInventorySchema);
inventoryItem Model:
const inventoryItemSchema = mongoose.Schema(
{
name: {
type: String,
required: true,
},
quantity: {
type: Number,
required: true,
},
available: {
type: Number,
required: true,
},
},
{
timestamps: true,
}
);
module.exports = mongoose.model("inventoryItem", inventoryItemSchema);
you got it wrong here
// Get the reserved list
const reservedDetails = await reserveInventory
.findOne({ memberID: id })
.select("itemsList")
.populate({ path: "itemsList.item"});

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?

Mongoose error with PUT request but not with POST or GET

I have a schema that looks like:
const houseSchema = new mongoose.Schema({
address: {
type: String,
required: true,
trim: true,
},
city: {
type: String,
required: true,
},
roofType: {
type: String,
//required: true,
},
repairType: {
type: String,
//required: true,
},
numFloors: {
type: Number,
//required: true,
},
isOwner: {
type: Boolean,
//required: true,
},
isGated: {
type: Boolean
},
includeFlat: {
type: Boolean
},
addedBy: [
{
name:{
type: String
},
time:{
type: String
},
}
],
});
const customerSchema = new mongoose.Schema({
firstName: {
type: String,
required: true,
trim: true,
},
lastName: {
type: String,
required: true,
trim: true,
},
phoneNumber: {
type: String,
required: true,
},
email: {
type: String,
},
//array of houseSchema objects
properties: [
houseSchema
],
});
And my endpoint that is used to update one of the 'properties' is:
router.route('/property').post(async (req,res) => {
const body = req.body;
Customer.updateOne({_id: req.query.id, properties: {$elemMatch: {_id: req.query.pId}}},
{
$set: {
"properties.$.address": body.address,
"properties.$.city": body.city,
"properties.$.roofType": body.roofType,
"properties.$.repairType": body.repairType,
"properties.$.numFloors": body.numFloors,
"properties.$.isOwner": body.isOwner,
"properties.$.isGated": body.isGated,
"properties.$.includeFlat": body.includeFlat
}
},
function(err){
if(err){
res.status(400).json('Error: ' + err);
}
else{
res.json('Property Updated!');
}
}
)
});
The endpoint works mostly fine (it returns the customer and all properties when i only search for and want to modify one of the 'properties') but only when it is a post or a get request and when it is a put request, the error says
Error: ValidationError: firstName: Path firstName is required., lastName: Path lastName is required., phoneNumber: Path phoneNumber is required.
I dont know if its a big deal or not, but I do not know why this is happening and would like to know. Just to be clear, the goal of this endpoint is to find one of the properties and update its values, not to change anything about a customer or any of their other properties.

MongoDB: Find items with the user id

I have a product collection and a user collection where I reference user to my product collection.
So far what I am trying to achieve here is to get only the products that are created by that user.
const getOwnerProduct = expressAsyncHandler(async (req, res) => {
const activeUser = await User.findById(req.user._id)
const pageSize = 10
const page = Number(req.query.pageNumber) || 1
const items = { user: { _id: activeUser } }
const count = await Product.countDocuments({ ...items } )
const products = await Product.find({ ...items }).limit(pageSize).skip(pageSize * (page - 1))
res.json({ products, page, pages: Math.ceil(count / pageSize) })
})
Here's the Product Schema:
const productSchema = mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
name: {
type: String,
required: true
},
price: {
type: Number,
required: true,
},
description: {
type: String,
required: true
},
email: {
type: String
},
rating: {
type: Number,
required: true,
default: 0
},
image: {
type: String,
required: true,
default: 0
},
}, { timestamps: true
})
And here's the userSchema:
const userSchema = mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
phone: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
role: {
type: String,
enum: ['administrator', 'productOwner', 'regular'],
default: 'regular'
}
}, { timestamps: true
})
Here's the router:
app.use('/api/products', productRoutes)
router.route('/').get(getProducts, admin).get(getOwnerProducts, productOwner)
For some reason this doesn't work. I think my query on mongodb is not correct.
Any idea what am I missing here?
Here instead of const products = await Product.find({ ...items }) you can try
await User.findById(req.user._id).forEach(element =>{Product.find({user=element._id})});
or
await User.findById(req.user._id).forEach(element =>{Product.find(user=element._id)});

MongoDB: Set and get Sub Document Schema

I'm using mongoose and I have users collection shown below, but I now want to allow the user to save a number of articles, an article has a title, subtitle, and body, One user can have many articles.
How can I restructure the users collection to allow the articles to be added
const userSchema: Schema = new Schema(
{
email: { type: String, required: true, unique: true },
fullName: { type: String, required: true },
password: { type: String, required: true },
},
{
timestamps: true,
}
);
I'm using the below to set new data to the user's collection, how do I adapt it to allow me to set and get the new articles detailed above?
const confirmed = await userModel
.findOneAndUpdate(
{ email },
{
$set: { password },
}
)
.exec();
You can set the option strict: false and add(save) new fields to your schema.
const userSchema: Schema = new Schema(
{
email: { type: String, required: true, unique: true },
fullName: { type: String, required: true },
password: { type: String, required: true },
},
{
strict: false,
timestamps: true,
}
);
Here is the docs