Updating nested schema in mongoose [duplicate] - node.js

This question already has answers here:
mongoose. updating embedded document in array
(3 answers)
Closed 7 years ago.
I have a nested item schema in an invoice schema as given below :
var InvoiceSchema = new db.Schema({
title: {
type: String,
required: true
},
description: String,
clientId: db.Schema.ObjectId,
companyId: db.Schema.ObjectId,
poNumber: Number,
invoiceNumber: {
type: Number,
default: 1000
},
taxApplied: {
type: Boolean,
default: false
},
feeApplied: {
type: Boolean,
default: false
},
lastUpdated: {
type: Date,
default: Date.now
},
createdOn: {
type: Date,
default: Date.now
},
status: {
type: String,
enum: ['presented', 'entered', 'hold', 'paid',
'partially paid', 'reversed', 'void'],
required: true
},
invoiceItems: [InvoiceItemSchema]
});
var InvoiceItemSchema = new db.Schema({
invoiceId: {
type: db.Schema.ObjectId,
required: true
},
description: String,
qty: Number,
rate: Number,
isFlatFee: {
type: Boolean,
default: false
}
});
I am able to create a new invoiceItem and push it directly into the invoice invoiceItems array, and read it when it's in there, but I am having a lot of trouble trying to update and delete. I was looking at this site here
http://tech-blog.maddyzone.com/node/add-update-delete-object-array-schema-mongoosemongodb
But I couldn't seem to get any of that to work.
I know in that blog he is using $set to update things but it looks like it only updates one field and I want to update any field based on user input and not a hard coded field. I don't have any code to show right now because I am quite lost but some help would be appreciated!

If you have a reference to the Invoice from your InvoiceItem you shouldn't really need to save the items in a list in Invoice. If you want to get that list you could simple do a query like:
InvoiceItem.find({invoiceId: invoiceId}, function(err, items) {
...
})
Now this will make it much easier to update as you only need to update each InvoiceItem object and just keep the reference to the Invoice.
Hope this helped you out.

Related

Modified model in node.js not reflecting on MongoDB

I just modified my model Order for my API because I need a value to pass a condition. But unfortunately, my new set of properties (orderStatus) on my collection did not reflect on my MongoDB database.
I don't need to input a value for the property (orderStatus) since I set a default value ("Pending"). I tried to delete the entire collection orders to see any changes but there were none. Is there something else I need to do on my MongoDB or any command on the git?
Here is my code for my model
const mongoose = require("mongoose");
const orderSchema = new mongoose.Schema({
userId: {
type: String,
required: [true, "User ID is required!"]
},
products: [
{
productId: {
type: String,
required: [true, "Product ID is required!"]
},
quantity: {
type: Number,
required: [true, "Quantity is required!"],
min: 1,
default: 1
},
subtotal: {
type: Number,
required: [true, "Subtotal is required"],
default: 0
}
}
],
totalAmount: {
type: Number,
required: [true, "Total Amount is required!"],
default: 0
},
orderStatus: {
type: String,
required: [true, "Order Status is required!"],
default:"Pending"
},
purchasedOn: {
type: Date,
default: new Date
}
});
module.exports = mongoose.model("Order", orderSchema);
and a screenshot of my database
I will really appreciate your help! Thank you so much!
Your documents which were already created will not reflect your new schema field. Since those fields only will get reflected on the update only. So, add orderStatus as pending as the default. You must migrate those documents by the update method. This is going to be a one-time process.
So, in the terminal, you can write the following code and run
db.collection.update({}, {$set: {orderStatus: "Pending"}}, {upsert: true, muti: true})
Or you are comfortable with the code itself you can write your update code in your project itself like this
await orderModel.updateMany({}, {$set: {orderStatus: "Pending"}}, {upsert: true})
and make an API and call this code.
In this process, you will see that in your documents that new key called orderStatus with pending value has been created.

Is there any other method for deleting a data in mongoose after a given time

const notificationSchema = mongoose.Schema({
type:{
type: String
},
message:{
type: String
},
userId:{
type: String,
required: true,
},
timestamp:{
type: Date,
default: new Date()
},
expireAt: {
type: Date,
default: Date.now,
index: { expires: '5m' },
},
})
My data is not getting automatically delete in mongoose, Is something wrong with my model? Here is my Structure of model.Can anyone help
const notificationSchema = mongoose.Schema({
type:{
type: String
},
message:{
type: String
},
userId:{
type: String,
required: true,
},
{
timestamps: true
}
});
notificationSchema.index({createdAt: 1},{expireAfterSeconds: 3600});
Each field in the collection will be deleted after 3600seconds
There's several ways, but one that pops to mind is TTL.
"TTL indexes are special single-field indexes that MongoDB can use to automatically remove documents from a collection after a certain amount of time or at a specific clock time."
Find out more here > https://docs.mongodb.com/manual/core/index-ttl/
And for mongoose > https://github.com/mongoosejs/mongoose-ttl

Mongodb, mongoose, Schema structure. get a collection into a field of other collection

I have a schema "Questions" it has like a dozen of questions in it, I can add and delete those questions, I need this collection reflected in a field of other collection - "User" with one additional field (nested in options).
Question Schema:
var QuestionScema = new mongoose.Schema({
key: { type: String, required: true },
label: { type: String, required: true },
name: { type: String, required: true },
page: { type: String, required: true },
type: { type: String, required: true },
options: [{
key: {type: String, required: true},
value: {type: String, required: true}
}],
});
User Schema:
var UserSchema = new mongoose.Schema({
Name: { type: String, required: true },
Email: { type: String, required: true, unique: true },
Password: { type: String, required: true },
//this is where I need to reflect a Questions collection on each user,
//so that it will look something like this//
Questions: [{
key: {type: String, required: true},
//here can be all other fields from Questions collection, that is not a problem
options: [{
key: {type: String, reuired: true},
value: {type: String, reuired: true},
counter: {type: Number, default: 0} //this is the additional field
}]
}],
//
Notifications: [{
Title: { type: String },
Data: { type: String },
Created: { type: Date, default: Date.now }
}]
});
I can't figure out how to do that.
I have another collection of users, say User2 that will answer those questions from Questions collections and I need to keep track on Users schema (not User2, there I just save questions and answers) of how many times an option for that question is chosen.
A Questiuons entry can look like this:
{
key: Haveyouseenthismovie,
label: Have you seen this movie?,
name: Have you seen this movie?,
page: 1,
type: dropdown,
options: [{
key: yes,
value: yes
}, {
key: no,
value: no
}]
}
I want it to work like that (reflect a collection in field of each User) so I don't have to check if that question is in User collection if not add and if it is, is there an option that I need if it is than increment, if not than add that option (that user selected from options in that question in Questions schema) and increment. That looks like a bummer. So I figured that it will be better if that field will reflect a collection and I will just increment the option that I need on a question that I need.
Please help me figure that out, I don't have enough practise in mongo so I struggle with it sometimes :)
I don't think there is a way to reflect a collection in another document as the way you seem to wish it.
As I understand, the following options are available for you:
Embed the entire question document inside the User documents in User Collection.
Just maintain the '_id' of the question document in the User document in User Collection.
Please read on Data Modelling concepts & maintaining relationship between documents from Mongo DB Page https://docs.mongodb.com/manual/applications/data-models-relationships/

MongoDB Aggregation based on corresponding array index matches for a chatting application

I want to implement an aspect of chatting application, i.e number of unseen / new messages for a particular chat.
Here's my chat Schema :
var chatSchema = new Schema({
name: { type: String, default: "friend_chat" },
chat_type: { type: String, default: "group" },
lastMessage: {
type: Schema.Types.ObjectId,
ref: 'Message',
default: ObjectId("000000000000000000000000")
},
participants: [{
_id: { type: Schema.Types.ObjectId, ref: 'Member' },
//used to keep track of new messages/messages count
lastMessageId: { type: String, default: "000000000000000000000000" },
//status can be admin,blocked,member
status: { type: String, default: "member" }
}],
isDeleted: { type: Boolean, default: false }
})
Here's my Message Schema :
var messageSchema = new Schema({
senderId: { type: Schema.Types.ObjectId, ref: 'Member' },
type: String,
content: String,
timeCreated: { type: Date, default: Date.now() },
chatId: { type: Schema.Types.ObjectId, ref: 'Chat' },
isRead: { type: Boolean, default: false },
isDeleted: { type: Boolean, default: false }
})
So the lastMessageId key in the participants arrays basically informs of the Id of the last Message the participant has seen. Therefore, to quickly retrieve the number of unseen Messages for a "single" chat window,how can I do this:
Message.aggregate([{$match:{chatId:INPUT_CHAT_ID,
senderId:PARTICIPANT'S_ID/req.session.userId,_id:
{$gt:participants.index.lastMessageId}}}])
For the above what should be the approach for getting the index.
Currently I have just implemented a linear search at frontend which gives me the lastMessageId as a parameter in the request to get around the problem but I want to know what should be the approach here.
Also suppose by linear search at the frontend,I am able to get the index,since frontend also has the copy of chat document(mongodb document) for displaying. Now I want to query the same thing but for multiple chats. Of course using Message.aggregate for each chatId is inefficient so what is the recommended way here.Currently from the front end I receive a JSONObject "chats" of this form:
`{ids:CHAT_IDs_array,last_Message_Ids :LAST_MESSAGE_IDS_array} `
in order meaning that the first index of CHAT_IDs array corresponds to first index of LAST_MESSAGE_IDS array
My attempted,incomplete,appraoch for this problem is as below :
`Message.aggregate([{chatId:{$in:chats.id},senderId:req.session.userId, _id:{$gt : ????}}])`
How to possibly make chats.id array index correspond with chats.last_Message_Ids index.
Also I would be appreciative if the answer doesn't impose any changes to the "Schema". Thanks

Mongoose - How to Specify and Delete Dependent Relations? [duplicate]

This question already has answers here:
Automatically remove referencing objects on deletion in MongoDB
(8 answers)
Closed 9 years ago.
With MongoDB and Mongoose, How can I mark objects as dependent on their relations so that if the Parent object is deleted, all of the children objects dependent on it will be deleted as well. For instance, how can I have all articles by an author be automatically deleted if the author is deleted?
var AuthorSchema = new Schema({
created: {
type: Date,
default: Date.now
},
name: {
type: String,
default: '',
trim: true
}
});
var ArticleSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true
},
content: {
type: String,
default: '',
trim: true
},
author: {
type: Schema.ObjectId,
ref: 'Author'
}
});
If you want to do something like mysql's "foreign key on delete cascade" where if you delete a parent, children are automatically deleted, then it is not possible in pure mongodb.
In order to achieve this, you have to implement it in your application logic. When you delete an author you have to run another delete on the article collection based on the authorID. Do not forget to put an index on this field.

Resources