This is the comment key pair I have in my post model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const postSchema = new Schema({
user:{
type:Schema.Types.ObjectId,
// required:true,
refPath:'onModel'
},
onModel:{
type:String,
enum:['Doctor','Patient']
},
text:{
type:String,
required:true
},
comments:[{
user:{
type:Schema.Types.ObjectId,
refPath:'onModel'
},
reply:{
type:String
},
date:{
type:Date,
default:Date.now
}
}],
likes:[{
user: {
type: Schema.Types.ObjectId,
ref: 'Patient'
}
}]
})
module.exports= post = mongoose.model('post', postSchema);
When I try pushing object to the likes array by running the following code, it fails. The filter part works fine, just some problem with the update part which ends up executing catch block.
Post.updateOne({ _id: req.params.postid, "likes": { $ne : { user:
authorizedData.jwt_payload.patient._id }}},
{ "$set" : { "likes.$.user": "authorizedData.jwt_payload.patient._id"
}})
.then(re => res.json(re))
.catch(err => res.json("already liked"))
Will really appreciate any help.
Please make changes as below :
const mongoose = require('mongoose');
const patientObjectID = mongoose.Types.ObjectId(authorizedData.jwt_payload.patient._id);
Post.updateOne({
_id: req.params.postid,
'likes.user': {
$ne:
patientObjectID
}
},
{ $push: { likes: { user: patientObjectID } }
}).then(re => res.json(re)).catch(err => res.json("already liked"))
Couple of changes need to be done, So When you've a schema like this ::
likes: [{
user: {
type: Schema.Types.ObjectId,
ref: 'Patient'
}
}]
You need to pass an ObjectId() to user field but not a string, So
first we're converting string to ObjectId() & passing it in query.
Also $set is used to
update existing or insert new fields in a document, but when you wanted to push
new values to an array field in a document then you need to use
$push(this seems to be a normal update operation on a field, but here we're not replacing the likes array, rather we're just adding few more elements to it - different kind of update though, So that's why we need to use $push).
As you already have below filter, we're just doing $push assuming what we're pushing is not a duplicate but in the other way you can blindly use $addToSet to do the same without having to use below filter criteria :
"likes": {
$ne: {
user:
patientObjectID
}
}
About your question on $(update) why it isn't working ? This should be used to update the elements in an array, it helps to update first matching element in an array based on filter criteria, but what you wanted to do here is to add few more elements but not updating existing elements in likes array.
Here you should not send "already liked" in catch block, it should be a custom error for an actual error, in .then(re => res.json(re)) you need to check write result of update operation if anything updated you need to send added user, if not you need to send "already liked".
Hope this solves all your questions :-)
Try using $push aggregation which is used for pushing objects to inner arrays in mongoDB. Your update query should be something like the following:
Post.updateOne({ _id: req.params.postid, "likes": { $ne : { user:
authorizedData.jwt_payload.patient._id }}},
{ "$push" : { "likes": authorizedData.jwt_payload.patient._id
}})
.then(re => res.json(re))
.catch(err => res.json("already liked"))
Related
I need a function to remove particular objects from a nested array ,please check the code as follow ,I have already tried a lot times ,but fail ..Could you please help me ?Thank you so much in advance!
UserSchema :
userName: {
type: String,
},
specialList: [
{
type: mongoose.Types.ObjectId,
ref: "Friend",
},
],
FriendSchema:
userName:{
type:string
}
Now ,I need a function to delete some of the friends in a user's specialList by their user's id,
For instance ,
//this is not working like I wish ...I have no idea what is going on ...
const needToRmoveList = ["123","456"];
await UserInfo.findOneAndUpdate(
{ _id: "345" },
{ $pull: { specialList: { id: { $in: [needToRmoveList] } } } },
{ new: true }
);
In my Nodejs and Express app, I have a mongoose User schema, a Post schema and a Comment schema as follows:
const UserSchema = new Schema({
username: {
type: String,
required: true,
unique: true
},
password: String,
posts : [
{
type : mongoose.Schema.Types.ObjectId,
ref : 'Post'
}
]
});
const PostSchema = new Schema({
author : {
type : mongoose.Schema.Types.ObjectId,
ref : 'User'
},
createdAt: { type: Date, default: Date.now },
text: String,
comments : [
{
type : mongoose.Schema.Types.ObjectId,
ref : 'Comment'
}
],
});
const CommentSchema = new Schema({
author : {
type : mongoose.Schema.Types.ObjectId,
ref : 'User'
},
createdAt: { type: Date, default: Date.now },
text: String
});
I have coded the general CRUD operations for my User. When deleting my user, I can easily delete all posts associated with that user using deleteMany:
Post.deleteMany ({ _id: {$in : user.posts}});
To delete all the comments for all the deleted posts, I can probably loop through posts and delete all the comments, but I looked at mongoose documentation here and it seems that deleteMany function triggers the deleteMany middleware. So In my Post schema, I went ahead and added the following after defining schema and before exporting the model.
PostSchema.post('deleteMany', async (doc) => {
if (doc) {
await Comment.deleteMany({
_id: {
$in: doc.comments
}
})
}
})
When deleting user, this middleware is triggered, but the comments don't get deleted. I got the value of doc using console.log(doc) and I don't think it includes what I need for what I intend to do. Can someone tell me how to use the deleteMany middleware properly or if this is not the correct path, what is the most efficient way for me to delete all the associated comments when I delete the user and their posts?
deleteMany will not give you access to the affected document because it's a query middleware rather than a document middleware (see https://mongoosejs.com/docs/middleware.html#types-of-middleware). Instead it returns the "Receipt-like" object where it tells it successfully deleted n objects and such.
In order for your hook to work as expected, you'll need to use something other than deleteMany, such as getting all of the documents (or their IDs), and loop through each one, using deleteOne.
I have a json array reorderList for a topic:
const reorderList = [
{ _id: '5e6b419c76a16d5c44d87132', order: 0 },
{ _id: '5e6b41a276a16d5c44d87139', order: 1 },
{ _id: '5e6b41a776a16d5c44d87140', order: 2 }
]
And my TopicSchema is like this:
var TopicSchema = new Schema({
topicTitle: String,
topicQuestion: [
{
questionTitle: String,
answer: String,
order: Number
}
]
}
Now I want to update my topic questions order based on the reorderList's _id.
But the below statement will replace all the things from topicQuestion (e.g. questionTitle and answer will be removed)
Topic.findOneAndUpdate(
{ '_id': topicId },
{ $set: { 'topicQuestion': reorderList } }, //replaces here
{ upsert: true },
function (err, response) {
...
});
How to update it based on reorderList and also keep the original data inside topicQuestion?
The schema that you're using is badly designed. What you can do here is create another schema, TopicQuestionSchema and put a ref to the topic it belongs to.
var TopicQuestionSchema = new Schema({
questionTitle: String,
answer: String,
order: Number,
topic: {type: ObjectId, ref: 'Topic'} // the name of your model
}
This way you can still keep track of the topic the questions belong to, and still be able to update the order easily.
I have 2 mongo schemas related one with the other using ObjectId:
var User = new Schema({
username: {
type:String,
unique: true
},
password: {
type:String
},
verified: {
type: Boolean,
default: false
},
lastActivity:{
type:Date,
default:Date.now
}
});
And a watitingRoom schema with lists all the users:
var WaitingRoom = new Schema({
lastActivity:{
type:Date,
default:Date.now
},
clients: [{
type : mongoose.Schema.ObjectId,
ref: 'User'
}],
videocalls: [{
type: mongoose.Schema.ObjectId,
ref:'VideoCall'
}]
});
So, I want to 'refresh' my clients array pulling all the clients which a lastActivity less than the current time. I tried it by using the $pull tool present in mongoose. After googling and mixing different examples I tried things like:
WaitingRoom.findOneAndUpdate({}, { lastActivity: new Date(),
$pull : {clients : {"clients.lastActivity": { $lt: new Date() }}}
}, options)
.populate("clients")
.exec( function(error, waitingRoom) {
if (err) { return res.status(500).send({ msg: err.message }); }
})
Which finds the unique waiting room, updates the lastActivity field and tries to pull all the clients that has a clients.lastActivity less than the current date.
(Obviously this snipped code doesn't work)
The problem is that I didn't find any documentation or example that explains if it is possible to pull elements from a referred ObjectId schema using a nested condition clients.lastActivity
You need to first find the ids from User database and then need to $pull them from the WaitingRoom database
User.find({ lastActivity: new Date() }).then((users) => {
const ids = []
users.map((user) => {
ids.push(user._id)
})
WaitingRoom.update({}, { $pull: { clients: ids }}, { multi: true }).then(() => {
console.log('removed')
})
})
I'm trying to make the following schema to work:
var FormSchema = new mongoose.Schema({
form_code: { type: String, unique: true },
...
});
var UserSchema = new mongoose.Schema({
...
submissions: [{
form_code: { type: String, unique: true },
last_update: Date,
questions: [{
question_code: String,
answers: [Number]
}]
}],
});
The rationale here is that a user can have many unique forms submitted, but only the last submission of each unique form should be saved. So, ideally, by pushing a submission subdocument when updating a user, the schema would either add the submission object to the set, or update the subdocument containing that form_code.
The following code doesn't work as desired (it pushes the new subdocument even if the form_code is already present):
User.findOneAndUpdate(
{ _id: user.id },
{ $addToSet: { submissions: submission_object } },
function (err, user) {
// will eventually have duplicates of form_code at user.submissions
}
);
The above schema clearly doesn't work, what must be changed to achieve that "upsertToSet"?