How to make the mongoose update array work properly? - reactjs

this is my schema.it has a user field and an array of object which contains a text message and direction will hold a either sent or received value.
const MessageSchema = new mongoose.Schema({
user:{type: String,required: true},
textArray:[
{
text:{type: String,required: true},
direction:{ type: String,required: true }
}]
});
This is the router code.btw should there be double quotes on the keys in var textmessage?
router.post('/',async(req,res)=>{
const {user,text,direction}=req.body;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
var textmessage={
"text":text,
"direction":direction
}
const doc = await Message.updateOne(
{ user: user },
{ $set: { user:user,$push:{textArray:textmessage}} },
{ upsert: true },
function(err,result){
if (err){
console.log(err);
}
else{
console.log(result)
res.send(result)
}// Make this update into an upsert
});
})
this is how it showsup in mongodb.the user is working ok but when i click theres is nothing under textArray.What am I doing wrong exactly?

you are using await with callback function , which is wrong :
const filter = { user: user };
const update = { $push:{textArray:textmessage}};
let doc = await Message.findOneAndUpdate(filter, update, {
new: true,
upsert: true
});
console.log('doc=',doc);

Related

Document not creating using MongoDB Session

I am trying to implement MongoDB session but not able to achieve it because of less references available on the internet. Also when I run the below code it stuck at the create user method inside try catch block and because of that it is not saving a document inside collection. Help with this.
const mongoose = require("mongoose");
// Declare the Schema of the Mongo model
const userSchema = new mongoose.Schema({
userName: {
type: String,
required: true,
},
});
// Declare the Schema of the Mongo model
const productSchema = new mongoose.Schema({
productName: {
type: String,
required: true,
},
});
//Export the model
const UserModel = mongoose.model("User", userSchema);
const ProductModel = mongoose.model(`Product`, productSchema);
(async () => {
// Connecting
try {
await mongoose.connect(`mongodb://127.0.0.1:27017/Mongo_Transaction`, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log(`Connected`);
// Initiating Mongodb Session
const session = await mongoose.startSession();
session.startTransaction();
try {
// Creating User
const user = await UserModel.create(
[
{
userName: "Bhavesh",
},
],
{ session: session }
);
console.log(user);
// Creating Product
const product = await ProductModel.create(
[
{
productName: "Rahul",
},
],
{ session }
);
// Commit Session
await session.commitTransaction();
session.endSession();
console.log(`completed`);
} catch (err) {
await session.abortTransaction();
session.endSession();
}
} catch (err) {
console.log(err.stack);
}
})();

Mongoose/Mongodb getting .deleteOne is not a function

When I click to delete a post, my console is saying TypeError: post.user.posts.deleteOne is not a function. It giving me this error after deleting.
const post = await Post.findByIdAndDelete(id).populate('user'); This code I am deleting the post from Post Schema
await post.user.posts.deleteOne(post)This code is to delete the post from the User Schema. I populated user and assigned it to post and then delete the user's post from this code, but I'm getting the error here.
Below is the controller code
export const deletePost = async (req, res) => {
const { id } = req.params;
try {
const post = await Post.findByIdAndDelete(id).populate('user');
await post.user.posts.deleteOne(post)
if (!post) {
return res.status(500).json({ message: "Unable To Delete" })
}
res.status(200).json({ message: "Deleted Successfully" })
} catch (error) {
console.log(error);
}
}
Client side delete request
const handleDeleteTrue = async () => {
try {
const { data } = await api.delete(`/post/${id}`)
console.log(data)
window.location.reload();
} catch (error) {
console.log(error.response.data.message);
}
};
User model schema
import mongoose from 'mongoose';
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
username: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true,
unqie: true
},
password: {
type: String,
required: true,
minlength: 6
},
posts: [{ type: mongoose.Types.ObjectId, ref: "Post", required: true }]
});
export default mongoose.model('User', userSchema);
Im able to delete the post from the post model schema, but in this pic, which shows the user model schema, that same post that was deleted is not deleted here. This is the problem Im trying to solve.
What I can seem to understand in your function below is that you're trying to delete a single post and also checking if post exists first
export const deletePost = async (req, res) => {
const { id } = req.params;
try {
const post = await Post.findByIdAndDelete(id).populate('user');
await post.user.posts.deleteOne(post)
if (!post) {
return res.status(500).json({ message: "Unable To Delete" })
}
res.status(200).json({ message: "Deleted Successfully" })
catch (error) {
console.log(error);
}
}
I'd suggest you try this
export const deletePost = async (req, res) => {
const { id } = req.params;
try {
//check if document exists in mongoDB collection
if (!mongoose.Types.ObjectId.isValid(id)) {
return res.status(500).json({ message: "Unable To Delete" }) }
await Post.deleteOne(id)
res.status(200).json({ message: "Deleted Successfully" })
catch (error) {
console.log(error);
}
}
I found out the answer. My user model schema for post was an array so I had to use $pull to delete it.
This is the code that worked for me
await post.user.posts.pull(post)
await post.user.save()
You can't use findOneAndDelete on populate to delete one object from an array. it doesn't work that way. Use This Instead.
const result = await User.findOneAndUpdate(
{ _id: Id },
{ $pull: { post:PostId } },
{ new: true }
);
You can find More on Pull and Push Operations on BlogLink

Mongoose deleting subdocuments from arrays using $pull

Hi I have a comment and post model that has a one-to-many relationship. It successfully creates a comments array and pushes the object id correctly, but when I try to delete a comment using $pull It doesn't delete or show errors just returns the object back unchanged and also I'm not sure how to update subdocuments either , it doesn't work
In comment.js
const mongoose = require("mongoose");
const AutoIncrement = require('mongoose-sequence')(mongoose);
const CommentSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
content:{
type: String,
required: true
},
createdAt:{
type: Date,
default: new Date()
},
})
CommentSchema.plugin(AutoIncrement, {inc_field: 'commentID'});
module.exports = mongoose.model("Comment", CommentSchema);
In post.js
const mongoose = require("mongoose");
const AutoIncrement = require('mongoose-sequence')(mongoose);
const PostsSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
createdAt:{
type: Date,
default: new Date()
},
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
});
PostsSchema.plugin(AutoIncrement, {inc_field: 'postID'});
module.exports = mongoose.model("Post", PostsSchema);
For the routes
router.post("/:id/comments", CommentController.createComment)
router.get("/:id/comments", CommentController.viewComments)
router.delete("/:id/comments/:commentID", CommentController.deleteComment)
router.patch("/:id/comments/:commentID", CommentController.updateComment)
And the controllers
const commentsModel = require("../models/comments")
const PostsModel = require("../models/posts");
const mongoose = require("mongoose")
const objID = mongoose.Types.ObjectId;
async function createComment(req, res){
try{
const comment = await commentsModel.create(req.body)
const data = await PostsModel.findOneAndUpdate(
{postID: req.params.id},
{$push: {comments: objID(comment._id)}},
{ new: true, useFindAndModify: false }
)
res.status(200).json({data})
}catch (e) {
res.status(404).json(e.message)
}
}
async function viewComments(req, res){
try{
const data = await PostsModel.findOne({postID: req.params.id}).populate("comments");
if(!data){
return res.status(404).json({msg: "No data found"});
}
res.status(200).json({comments: data.comments});
}catch (e) {
res.status(500).json(e.message);
}
}
async function deleteComment(req, res){
try{
const post = await PostsModel.update({ postID: req.params.id },
{
'$pull': {
comments: {
_id: objID(req.params.commentID)
}
}
}, {new: true});
if (!post){
return res.status(404).json({msg: "No post found"});
}
res.status(200).json({post});
}catch (e) {
res.status(500).json(e.message);
}
}
async function updateComment(req, res){
try{
const post = await PostsModel.findOneAndUpdate(
{"postID": req.params.id, "comments._id": objID(req.params.commentID)},
{
"$set":{
"comments.$.username": req.body.username,
"comments.$.content": req.body.content
}
}
)
if (!post){
return res.status(404).json({msg: "No post found"});
}
res.status(200).json({post});
}catch (e) {
res.status(500).json(e.message);
}
}

Mern stack bcrypt password works many times, and suddenly doesn't match

i have a strange problem and don't find the same so i search some help :) :
I make a mern stack social media, and first all is okay with register new user and logged in.
I'm on development of the app, so i login and logout a lot. And after a few times, i don't count, maybe 20 or 30, the password is not recognized, and i can't login with the account.
So i make a new user to continue my work, and the same thing happen after a few logins.
Here is my userSchema
const mongoose = require("mongoose");
const {isEmail} = require("validator");
const bcrypt = require("bcrypt");
function validEmail(email) {
if(!isEmail(email)) {
return false;
}
else {
return true
}
}
const userSchema = new mongoose.Schema(
{
pseudo: {
type: String,
required: true,
minLength: 3,
maxLength: 20,
unique: true,
trim: true
},
email: {
type: String,
required: true,
lowercase: true,
trim: true,
unique: true,
validate: validEmail
},
password: {
type: String,
required: true,
maxLength: 1024,
minLength: 6
},
dimension: {
type: String,
},
galaxy: {
type: String,
},
picture: {
type: String,
default: "./uploads/profil/random-user.png"
},
bio: {
type: String,
maxLength: 1024
},
followers: {
type: [String],
},
following: {
type: [String]
},
likes: {
type: [String]
}
},
{
timestamps: true,
}
)
// Play function before save into display: block
userSchema.pre("save", async function(next) {
const salt = await bcrypt.genSalt();
this.password = await bcrypt.hash(this.password, salt);
next();
})
userSchema.statics.login = async function(email, password) {
const user = await this.findOne({email});
console.log(user)
if(user) {
const auth = await bcrypt.compare(password, user.password);
if(auth) {
return user;
} else {
throw Error("Incorrect password");
}
}
throw Error("Incorrect email");
}
const UserModel = mongoose.model("user", userSchema);
module.exports = UserModel;
And here the login function in my auth.controller.js:
module.exports.signIn = async (req, res) => {
const { email, password } = req.body;
try {
const user = await UserModel.login(email, password);
const token = createToken(user._id);
res.cookie("jwt", token, {
maxAge: maxAge, sameSite: "none",
secure: true,
})
res.status(200).json({ user: user._id })
}
catch (err) {
const errors = signInErrors(err);
res.status(200).json({ errors });
// console.log(err)
}
}
It's my first project with back-end side, and i follow a tutorial from 2020 to make it, so maybe there is new best practices to do it now. But it seems very strange that it works fine with new user, and not after some connections. I hope someone have an idea to try to help me :)
I find this and try, seems to work for me after 2 days, with adding a condition on the pre hook like this:
userSchema.pre("save", async function(next) {
if(!this.isModified("password")) {
return next()
}
const salt = await bcrypt.genSalt();
this.password = await bcrypt.hashSync(this.password, salt);
next();
})
Hope it help someone

Need help saving a game to a user's favorited games

I'm receiving an error when trying to associate a saved game to the user that saves it. The error says "cannot read property push of undefined"
The user, and game can be read in the console. I think it may have something to do with the user model during the initial creation of the user, however I can't be sure. I did notice if I try to console.log(user.favGames) it will be returned undefined.
I've tried everything I can think of, I've re-written the controller roughly 10 times, to no avail.
user model
const mongoose = require('mongoose')
const bcrypt = require('bcrypt')
const SALT_ROUNDS = 6
const Schema = mongoose.Schema
const userSchema = new Schema(
{
username: { type: String, unique: true },
email: { type: String, unique: true, unique: true },
password: { type: String, required: true },
avatar: { type: String },
favGames: { type: Schema.Types.ObjectId, ref: 'Game', default: null },
comments: { type: Schema.Types.ObjectId, ref: 'Comment', default: null }
},
{
timestamps: true
}
)
userSchema.set('toJSON', {
transform: function(doc, ret) {
delete ret.password
return ret
}
})
userSchema.pre('save', function(next) {
const user = this
if (!user.isModified('password')) return next()
bcrypt.hash(user.password, SALT_ROUNDS, function(err, hash) {
if (err) return next()
user.password = hash
next()
})
})
userSchema.methods.comparePassword = function(tryPassword, cb) {
bcrypt.compare(tryPassword, this.password, cb)
}
module.exports = mongoose.model('User', userSchema)
game model
const mongoose = require('mongoose')
const Schema = mongoose.Schema
let gameSchema = new Schema({
name: { type: String, required: true },
boxArtUrl: { type: String, required: true },
twitchID: { type: String, required: true },
comments: { type: Schema.Types.ObjectId, ref: "Comment"}
})
module.exports = mongoose.model('Game', gameSchema)
game router
const express = require('express')
const router = express.Router()
const gamesCtrl = require('../../controllers/gameCtrl')
function isAuthed(req, res, next) {
if (req.user) return next()
return res.status(401).json({ msg: 'Unauthorized ' })
}
router.get('/')
router.post('/', isAuthed, gamesCtrl.addGame)
module.exports = router
game controller
const User = require('../models/user')
const Game = require('../models/Game')
function addGame(req, res) {
Game.create({
name: req.body.name,
twitchID: req.body.id,
boxArtUrl: req.body.box_art_url
})
.then(game => {
User.findById(req.user._id)
.then(user => {
console.log(game)
console.log(user.favGames)
// user.favGames.push(game)
// user.save()
})
.catch(err =>
console.log('error when updating user with new game', err)
)
})
.catch(err => console.log('error saving game', err))
}
module.exports = {
addGame
}
the error is flagged in my controller at user.favGames.push(game). Note that when a user creates a profile there are no games associated with their profile. I'm pretty sure I'm calling on the actual data instance of the model, not the model itself. Thanks in advance for your assistance.
Your favGames (and also comments) must be defined as array in user model like this.
const userSchema = new Schema(
{
username: { type: String, unique: true },
email: { type: String, unique: true, unique: true },
password: { type: String, required: true },
avatar: { type: String },
favGames: [{ type: Schema.Types.ObjectId, ref: 'Game', default: null }],
comments: [{ type: Schema.Types.ObjectId, ref: 'Comment', default: null }]
},
{
timestamps: true
}
)
Also user.save() returns a promise, so you need use then block, or await.
So the addGame function must be like this (I converted the code to async/await)
async function addGame(req, res) {
try {
let game = await Game.create({
name: req.body.name,
twitchID: req.body.id,
boxArtUrl: req.body.box_art_url
});
let user = await User.findById(req.user._id);
if (user) {
user.favGames.push(game);
await user.save();
res.status(200).send("game and user saved");
} else {
console.log("user not found");
res.status(404).send("user not found");
}
} catch (err) {
console.log("Err: ", err);
res.status(500).send("Something went wrong");
}
}
Looks like it's a matter of checking to see if it exists:
User.findById(req.user._id)
.then(user => {
if (!Array.isArray(user.favGames)) {
user.favGames = [];
}
user.favGames.push(game);
user.save();
})

Resources