Document not creating using MongoDB Session - database

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);
}
})();

Related

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);
}
}

How to make the mongoose update array work properly?

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);

Update query timing out after 10 seconds despite successfully submitting in React app

I have the following Schema:
const SubmitDebtSchema = new Schema ({
balance: [{
balanceDate: Date,
newBalance: Number
}]
});
And I have the following function which appends new objects into the array:
module.exports = async (req, res) => {
let newDateObject = {
balanceDate: req.body.balanceDate,
newBalance: req.body.newBalance
};
await SubmitDebt.findOneAndUpdate(
{ _id: req.query.id },
{ $push: { balance: newDateObject } },
{new: true, useFindAndModify: false}
);
};
However, despite the database successfully updating, it times out after 10 seconds with the following error message:
2020-11-23T16:51:57.138Z 25fa69c2-91a1-4a74-8034-af132d4d8eb3 Task
timed out after 10.01 seconds
Does anyone have any feedback for how to resolve this? It also doesn't push to my 'dashboard' upon successful submission.
Here's my Axios front-end call:
onSubmit = async (e) => {
e.preventDefault();
let newBalanceDate = new Date();
this.calculateUpdatedBalance()
await axios.post("/api/edit/editDebtBalance",
{
balanceDate: newBalanceDate,
newBalance: this.calculateUpdatedBalance(),
},
{
params: {
id: this.props.match.params.id
}
}
)
this.props.history.push('/dashboard');
}
EDIT: My full serverless function file:
const express = require("express");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
const SubmitDebt = require("../submit/submitDebtSchema");
require("dotenv").config();
const app = express();
app.use(bodyParser.urlencoded({
extended: true
}));
mongoose.connect(process.env.MONGO_URI);
module.exports = async (req, res) => {
let newDateObject = {
balanceDate: req.body.balanceDate,
newBalance: req.body.newBalance
};
return await SubmitDebt.findOneAndUpdate(
{ _id: req.query.id },
{ $push: { balance: newDateObject } },
{new: true, useFindAndModify: false}
);
};
How about you try returning the value?
A lambda function stops only when you return something, try this.
return await SubmitDebt.findOneAndUpdate(
{ _id: req.query.id },
{ $push: { balance: newDateObject } },
{new: true, useFindAndModify: false}
);
Notice that I only added return before the await statement, that's it.
Edit: Ahh.... I think this should work
let response = await SubmitDebt.findOneAndUpdate(
{ _id: req.query.id },
{ $push: { balance: newDateObject } },
{new: true, useFindAndModify: false}
);
return res.send(response)
since you're using an express app. I'm sorry I overlooked it previously.

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();
})

Generate mongoose schema for dynamically populated array of objects

This is my array of objects:
[
{
ready: true,
body: "Body 1"
},
{
ready: true,
body: "Body 3"
},
{
ready: true,
body: "Body 3"
},
]
Now if I want to generate a schema I'd normally do something like this:
const mongoose = require('mongoose');
const { Schema } = mongoose;
const BodySchema = new Schema({
});
mongoose.model('Body', BodySchema);
I need to know what to put inside the new Schema({}); declaration so it would accept the array of objects.
Thanks.
EDIT:
This is how I format data:
try {
const retrievedFull = await getFullData();
const data = await retrievedFull.map(({ready, body}) => ({
ready,
body
}))
const finalData = new Body(data) //instantiate Schema
return res.status(200).json({
success: true,
data: finalData
})
} catch(err) {
console.log(err);
}
The response from getFullData():
[
{
ready: true,
body: "Body 1",
other_stuff: "Stuff 1"
},
{
ready: true,
body: "Body 2",
other_stuff: "Stuff 2"
},
{
ready: true,
body: "Body 3",
other_stuff: "Stuff 3"
},
]
So, basically I strip all the properties I want and make a new array of objects.
So the data you want to store in database are two simple attributes, you can use the following schema :
const mongoose = require('mongoose');
const { Schema } = mongoose;
const BodySchema = new Schema({
ready: Boolean,
body: String,
});
const BodyModel = mongoose.model('Body', BodySchema);
About the way to store the data inside of the database :
try {
// Get the data from an external source
const externalData = await getFullData();
// Format the data
const formattedData = externalData.map(({
ready,
body,
}) => ({
ready,
body,
}));
// Insert the data in the database
const databaseData = await BodyModel.insertMany(formattedData);
// Returns the inserted data
return res.status(200).json({
success: true,
data: databaseData,
});
} catch (err) {
console.log(err);
}
Documentation of insertMany
I would define it this way:
const BodySchema = new Schema({
data: [{
ready: Boolean,
body: String
}]
});

Resources