I am trying to update a 'Board' model in mongoose using findByIdAndUpdate and the model has an array of 'items' (which are objects) on the model. I probably do not understand mongoose well enough but for some reason each item in the array gets an id generated, along with the Board. This is not a problem, it's quite handy actually, however, after doing a findByIdAndUpdate the id on each item has changed. This was quite surprising to me, I really thought they would stay the same. Could this be caused by updating all items in the array? Maybe mongoose is just throwing out the entire array and creating a new one when updating (maybe someone knows?). Anyways, my question is: Is there a way to update the model without changing these id's. I would really like them to stay consistent. The code I am using for update is
exports.updateBoard = asyncHandler(async (req, res, next) => {
let board = await Board.findById(req.params.id);
if (!board) {
return next(new CustomError(`Board not found with id of ${req.params.id}`, 404));
}
// Authorize user
if (board.user.toString() !== req.user.id) {
return next(new CustomError(`User ${req.user.id} is not authorized to update board ${board._id}`, 401));
}
req.body.lastUpdated = Date.now();
board = await Board.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true })
.select('-__v')
.populate({
path: 'user',
select: 'name avatar',
});
// 200 - success
res.status(200).json({ success: true, data: board });
});
and BoardSchema:
const BoardSchema = new Schema(
{
user: {
type: Schema.Types.ObjectId,
ref: 'User',
required: [true, 'Board must have a user'],
},
name: {
type: String,
required: true,
trim: true,
},
description: {
type: String,
required: false,
trim: true,
},
items: [
{
title: {
type: String,
required: true,
trim: true,
},
description: {
type: String,
required: false,
trim: true,
},
dateCreated: {
type: Date,
default: Date.now,
},
lastUpdated: {
type: Date,
default: Date.now,
},
},
],
columns: [
{
name: {
type: String,
required: true,
},
index: {
type: Number,
required: true,
},
show: {
type: Boolean,
required: true,
},
},
],
dateCreated: {
type: Date,
default: Date.now,
},
lastUpdated: {
type: Date,
default: Date.now,
},
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true },
},
);
Related
I have two collections in MongoDB database, Post and User. Each post contains the creator's ObjectId. When fetching all posts from the database, I want to add the name information, which is a field of User/creator. I tried to access the name field by post.creator.name, but it is not working.
const postSchema = new Schema(
{
title: {
type: String,
required: true,
},
category: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
imageUrl: {
type: String,
required: true,
},
creator: {
type: Schema.Types.ObjectId,
ref: "User",
required: true,
},
},
{ timestamps: true }
);
const userSchema = new Schema({
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
status: {
type: String,
required: true,
},
isExpert: {
type: Boolean,
required: true,
},
posts: [
{
type: Schema.Types.ObjectId,
ref: "Post",
},
],
});
exports.getPosts = (req, res, next) => {
Post.find({}).then((posts) => {
const postsWithAuthorName = posts.map(post => {
return {
...post,
name: post.creator.name
}
})
res.status(200).json({
posts: postsWithAuthorName,
});
});
};
Try this
Post.find({}).populate('creator', 'name')
See populate doc for reference.
When you query posts, creator is just an ObjectId, so you can't just call .name on it. To make it work you need to lookup this data by using e.g. populate.
I am trying to update an array, nested within an object in MongoDB document, using mongoose.
I have been over several similar questions, and only appeared to make a little success, then res.json return { acknowledged: false }, with no errors.
The goal is to push an object into the "likes" array inside reactions object
This is the document that I'm trying to update
_id: new ObjectId("63179b818ebed9da5b433ee0"),
thoughtText: "If Everything works out here, we're supposed to get a notification send to another guy by whomsoever leaves a comment or a like on this post.",
topic: 'Testing out the new notification codes for possible errors',
username: 'anotherguy',
userId: '63179a67849b0348e59d4338',
category: 'Secrets',
createdAt: 2022-09-06T19:12:01.345Z,
reactions: [
{
CommentLikeCount: 0,
mentions: 0,
reactionBody: 'Welcome to U-annon anotherGuy, this is your official first reaction on the site',
username: 'marryGold',
_id: new ObjectId("63179cd18ebed9da5b433ee8"),
reactionId: new ObjectId("63179cd18ebed9da5b433ee9"),
createdAt: 2022-09-06T19:17:37.829Z,
likes: []
},
Below is the query I'm currently using to update the document using updateOne.
EDIT: The schema.
// thought schema or post schema
const thoughtSchema = new Schema (
{
thoughtText: {
type: String,
required: true,
minlength: 1,
maxlength: 2000
},
topic:{
type: String,
required: true,
minlength: 1,
maxlength: 300
},
createdAt: {
type: Date,
default: Date.now,
get: createdAtVal => moment(createdAtVal).startOf('hour').fromNow()
},
username: {
type: String,
required: true,
},
userId:{
type: String,
required: true
},
category: {
type: String,
required: true,
},
reactions: [reactionSchema],
likes: [likeSchema],
},
{
toJSON: {
virtuals: true,
getters: true,
},
id: false,
}
The like schema is similar to the reaction schema,
//reaction schema
const reactionSchema = new Schema (
{
reactionId: {
type: Schema.Types.ObjectId,
default: () => new Types.ObjectId(),
},
reactionBody: {
type: String,
required: true,
},
username: {
type: String,
required: true,
},
userId:{
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now,
get: createdAtVal => moment(createdAtVal).startOf('second').fromNow()
},
mention: {
type: Object,
required: false
},
likes: [likeSchema],
CommentLikeCount: {
type: Number,
default: 0,
},
mentions: {
type: Number,
default: 0
}
},
{
toJSON: {
virtuals: true,
getters: true
},
id: false,
}
)
And this is the full controller function. including how I check to see if the same user already liked the comment
//Like comments
async likeComments(req, res){
console.log(req.body, req.params)
try {
const post = await Thought.findById(req.params.thoughtId)
const comment = post.reactions.find(x => x.reactionId.toString() === req.params.reactionId)
const liked = comment.likes.find(x => x.username === req.body.username)
if(!liked){
console.log('its open')
const data = await post.updateOne({"reactions.[reaction]._id": req.params.reactionId}, {$addToSet:{"reactions.$.likes": req.body}}, { runValidators: true, new: true })
console.log(data)
res.json(data)
}else{
console.log('already liked')
const data = await post.updateOne({"reactions.[reaction]._id": req.params.reactionId}, {$pull:{"reactions.$.likes": req.body}}, { runValidators: true, new: true } )
res.json(data)
}
} catch (error) {
console.log(error)
}
I've on this for the entire day, I'd really appreciate any help that I can get.
I have 2 schemas User and Restaurant, and user has an array of restaurants, am trying to reach when deleting the restaurant delete its reference from user automatically, am trying to reach it with the model.pre('remove')..but when I delete a restaurant the reference id it still exist in User.
Here is my User Schema:
const userSchema = new Schema(
{
email: {
type: String,
trim: true,
// required: true,
unique: true,
},
password: {
type: String,
// required: true,
min: 5,
},
stripeCustomerId: {
type: String,
// unique: true,
},
linkedAffiliateUser: {
type: String, //mongoose.Schema.Types.ObjectId,
},
restaurants: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Restaurant",
},
],
role: {
roleId: { type: Number, minlength: 1, maxlength: 1, required: true },
roleName: { type: String, trim: true, required: true },
},
// seperated schema
},
{ timestamps: true }
);
export default mongoose.model("User", userSchema);
and here is my Restaurant Schema:
const restaurantSchema = new Schema({
restaurantOwner: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
Name: {
type: String,
trim: true,
},
server: { type: mongoose.Schema.Types.ObjectId, ref: "ServerUser" },
restaurantLinkAccess: {
type: String,
required: true,
trim: true,
unique: true,
},
});
restaurantSchema.pre("remove", function (next) {
this.model("User")
.update(
{ restaurantSchema: this },
{ $pull: { comments: this._id } },
{ multi: true }
)
.exec(next);
});
export default mongoose.model("Restaurant", restaurantSchema);
I also tried to solve it like this:
restaurantSchema.pre("remove", function (next) {
this.model("User").remove({ $pull: { restaurants: this._id } }, next);
});
Please help.
I have following code for a chat application based on socket io.
const query={ chatID: chatId }
const update= {
$push: {
messages:{
message: message,
sendBy: sendById,
sendTo: sendTo
}
}
}
const options={upsert: true, new:true}
Chat.findOneAndUpdate(query, update, options, function(error, result) {
if (error){
console.log("error: "+error.message);
return;
}
io.emit("message", result.messages)
}).clone();
now if the chat id doesn't exists it creates new with query and update. But i want it like,
if the query doesnt exist, i have some more params to add to the document. How can i achieve that.
if i add the whole params in query , it wont find the document.
the foloowing is my schema
const ChatSchema = mongoose.Schema({
chatID: { type: String, required: true, unique: true },
participants: [
{ senderId: { type: mongoose.Types.ObjectId, unique: true, required: true } },
{ receiverId: { type: mongoose.Types.ObjectId, unique: true, required: true } }
],
messages: [
{
message: { type: String, required: true },
sendBy: { type: String, required: true },
sendTo: { type: String, required: true },
seen: { type: Boolean, default: false },
date: { type: Date, default: Date.now() }
},
],
})
I want to update the priority of a blog post if its older than say 2-3 days and i am not sure how to achieve this. In my route i try to identify if the blog post is older than 2 days, and if that was the case, it would change the priority from 'high' to ''. So far no luck and from what i read online, it seems that there may be npm packages that can achieve this for me.
Mongoose Schema
var blogSchema = new mongoose.Schema({
image: {
type: String,
trim: true
},
priority: {
type: String,
default: "",
trim: true
},
title: {
type: String,
trim: true
},
content: {
type: String,
trim: true
},
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
trim: true
},
username: {
type: String,
trim: true
},
name: {
type: String,
trim: true
},
},
slug: {
type: String,
unique: true,
trim: true
},
status: {
type: String,
trim: true
},
viewCount: {
type: Array,
timestamps: {
createdAt: 'createdAt',
updatedAt: 'updatedAt',
trim: true
}
},
category: {
type: String,
trim: true
},
categorySlug: {
type: String,
trim: true
},
tags: {
type: String,
trim: true
},
updated: {
type: Boolean,
default: false,
},
date: { type: Date, default: Date.now , trim: true},
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Comment',
trim: true
},
],
},{
timestamps: {
createdAt: 'createdAt',
updatedAt: 'updatedAt'
}
});
My Route
router.get('/', function (req, res) {
blog.find({ priority: ['high'] })
.sort({date: -1})
.limit(1)
.exec(function(err, high) {
if (err || !high) {
console.log(err);
req.flash('Troubleshooting Error')
redirect('/');
} else {
if(high && Date.now() > high.createdAt + 86400000 ) {
var priority = {slug: 'slug', priority: 'high'}
var newPriority = '';
blog.findOneAndUpdate(priority, newPriority,function(err, updated){
if(err) {
console.log(err);
} else {
console.log('Successfully updated priority');
}
});
}
};
});