Implementing Transaction in node js using mongoose - node.js

I am Trying to implement transaction in my project, since I would like to update more than one collection on the same api
I am sharing the sample code, I tried to understand the concept
sample code
const mongoose = require("mongoose");
const session = await mongoose.startSession();
session.startTransaction();
const opts = { session };
try {
const sample = await sample_table.findOneAndUpdate({
user_name : "nishanth"
},{status: "Inactive"},
{opts});
const transaction = await transaction_table.findOneAndUpdate({
bank_name : SBI
},{status: "Inactive"}, { opts });
await session.commitTransaction();
session.endSession();
return res.send({message: "success", sample_data: sample, transaction_data:
transaction});
}catch(err)
{
await session.abortTransaction();
session.endSession();
return res.send({err: err.message});
}
In the above code, I am trying to update two collections status to Inactive with a filter.
I had give an undefined variable for the transaction_table so the second update query will fail before commit and go to catch block and perform abortTransaction
When I use the above code, It updates the sample_table collection in db. could someone explain me where I am going wrong and share me a sample project for the above example
I am using "mongoose": "^5.13.14", version

Related

How to stop API GET request once data is fetched successfully

My question is strictly related to MEAN stack. I want to fetch the total count of documents stored in my MongoDB databse. My express server is working fine but on postman I can see still it is still making request even though i got correct count on console:
Here is my code:
api.js
const uri = 'mongodb://tanzee.......ue&w=majority'
const { MongoClient } = require("mongodb");
const client = new MongoClient(uri);
router.get('/totalmovies', function(req, res) {
run().catch(console.dir);
});
async function run() {
try {
await client.connect();
const database = client.db("mycollection");
const movies = database.collection("movies");
const estimate = await movies.estimatedDocumentCount();
console.log(`Estimated number of documents in the movies collection: ${estimate}`);
} finally {
await client.close();
}
}
I took help from the official doc of mongodb: https://docs.mongodb.com/drivers/node/usage-examples/count/
Output:
(node:15511) DeprecationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.
Estimated number of documents in the movies collection: 80
I'm new to this stack. Once the output is fetched, my code should stop the GET call immediately. Please point out my mistakes.
Your code is correct, the request is pending as you are not sending any response thats why the requester is still waiting to receive one. A simple fix is to send data back to the requester.
router.get('/totalmovies', async function(req, res) {
const result = await run();
// check how are you getting result when it is a success/failure
// apply condition same in the below if/else
// it just for reference, it might be correct though
if (result > 0) {
res.status(200).send(result);
} else {
res.status(404).send({'No Data in DB'});
}
});
(node:15511) DeprecationWarning: current URL string parser is
deprecated, and will be removed in a future version. To use the new
parser, pass option { useNewUrlParser: true } to MongoClient.connect.
for this to work:
const client = new MongoClient(uri, { useNewUrlParser: true })
Don't close and rebuild the connection for every request:
async function run() {
try {
await client.connect();
const database = client.db("mycollection");
const movies = database.collection("movies");
const estimate = await movies.estimatedDocumentCount();
console.log(`Estimated number of documents in the movies collection: ${estimate}`);
return estimate;
} catch (e){
console.error('Error in fetching the data from DB')
}
}

Node js route need to wait for processing of another request

We processing the order requests, on the time of multiple HTTP requests hitting the same route function means the function not working properly
Actually, we write the async await operation for all DB related queries
our coding example is
buyCtrl.orderPlace = async function (req, res, next) {
var response = await table1.find({exchange:ref_m}).sort({_id:-1}).limit(1);
if(response.length > 0)
{
var incRes = await table2.findOneAndUpdate({_id:1},{a:b}, {new: true});
var OrdersIns = new Orders();
OrdersIns.userid = userid;
OrdersIns.from = 'a';
OrdersIns.to = 'b';
await OrdersIns.save();
await compare(positiondetails[0]);
res.status(200).json({status:true,message:'Order placed successfully'});
}
}
const compare = async (curOrder) => {
var result = await Orders.find({userid:mongoose.Types.ObjectId(userid),type:opp}).sort({posTimestamp:1});
if(result.length>0)
{
for(var pi=0;pi<result.length;pi++)
{
if(parseFloat(curOrder.qty)==parseFloat(result[i].qty))
{
var updatedata = {a:b}
await Orders.findOneAndUpdate({_id:mongoose.Types.ObjectId(curOrder._id)}, updatedata, {new: true});
await Orders.remove({_id:mongoose.Types.ObjectId(result[i]._id)});
}
else
{
var updatedata = {a:b}
await Orders.findOneAndUpdate({_id:mongoose.Types.ObjectId(result[i]._id))}, updatedata, {new: true});
await Orders.remove({_id:mongoose.Types.ObjectId(curOrder._id)});
}
}
}
}
This is the flow we have I cannot paste my full code so make some example code
Please check and share your ideas
when we make an automation test with more concurrent requests the compare and update is not working properly
Thanks in advance
For atomic operations such as increment and decrement, this can be done using MongoDB's provided API. Another solution is to work with versioning, which MongoDB provides out of the box. The concurrent connection might update the object which changed before the update could take place.

Hi. How to use find query in mongoose - Express + MongoDB base

What I'm doing is trying to write logic for cart in my web-app what I'm creating. Problem what I'm dealing right now is that when I use query to find cart by id :
const isCart = await cartModel.findById("5f82372f2654ce1d18553ac4");
or like this
const isCart = await cartModel.find({ _id : "5f82372f2654ce1d18553ac4"} );
if cart exist with this id all works good it returns me this cart, but if in DB cart doesn't exist with this id then it throws me an error. WHY (pic below) ?? It would make more sense if it returns empty array or object so I can continue building logic of I want to do. But once it throws error it shuts down all further logic. I can't write if there is nothing found, create new cart and so on. Hopefully you got what I mean. Is it something I don't write correctly query or it is the way it is. If so, then I guess I should already control it on client side - if it returns error to a client side then client side sends new request to a new rout on creating a new cart and so on...
Here is solution what I did after someone told me that I might try do with try - catch
Here is a result, it works I'm not sure if this solution is right tho
async function sendCart (code, cart, res){
res.status(code).json({
status: "success",
data: {
cart
}
})
}
exports.createCart = async (req, res, next) => {
try{
const isCart = await cartModel.findById(req.params.id);
await sendCart(200, isCart, res);
}
catch(error){
const newCart = await cartModel.create({ items: [] });
await sendCart(201,newCart, res);
}
}

Unhandled Rejection (FirebaseError): No document to update

I'm still very new to coding so bear with me! I have followed a youtube course to build a note app and get a base to work from, but I'm now getting this error at random times when deleting the notes in firebase, hoping someone might be able to spot what's cooking here!
"Unhandled Rejection (FirebaseError): No document to update: projects/speakle-dc94b/databases/(default)/documents/notes/GdWPrQNxR3Z9TFMWmqOZ"
And it's referencing the node modules like so:
screenshot of the error in chrome
The code I have that interacts with firebase looks like this:
componentDidMount = () => {
firebase
.firestore()
.collection('notes')
.onSnapshot(serverUpdate => {
const notes = serverUpdate.docs.map(_doc => {
const data = _doc.data();
data['id'] = _doc.id;
return data;
});
console.log(notes);
this.setState({ notes: notes });
});
}
selectNote = (note, index) => this.setState({ selectedNoteIndex: index, selectedNote: note });
noteUpdate = (id, noteObj) => {
firebase
.firestore()
.collection('notes')
.doc(id)
.update({
title: noteObj.title,
body: noteObj.body,
timestamp: firebase.firestore.FieldValue.serverTimestamp()
});
}
newNote = async (title) => {
const note = {
title: title,
body: ''
};
const newFromDB = await firebase
.firestore()
.collection('notes')
.add({
title: note.title,
body: note.body,
timestamp: firebase.firestore.FieldValue.serverTimestamp()
});
const newID = newFromDB.id;
await this.setState({ notes: [...this.state.notes, note] });
const newNoteIndex = this.state.notes.indexOf(this.state.notes.filter(_note => _note.id === newID)[0]);
this.setState({ selectedNote: this.state.notes[newNoteIndex], selectedNoteIndex: newNoteIndex });
}
deleteNote = async (note) => {
const noteIndex = this.state.notes.indexOf(note);
await this.setState({ notes: this.state.notes.filter(_note => _note !== note) })
if(this.state.selectedNoteIndex === noteIndex) {
this.setState({ selectedNoteIndex: null, selectedNote: null});
} else {
this.state.notes.lenght > 1 ?
this.selectNote(this.state.notes[this.state.selectedNoteIndex - 1], this.state.selectedNoteIndex - 1) :
this.setState({ selectedNoteIndex: null, selectedNote: null });
}
firebase
.firestore()
.collection('notes')
.doc(note.id)
.delete()
.then(function() {
console.log("Document successfully deleted!");
}).catch(function(error) {
console.error("Error removing document: ", error);
});
}
}
It simply means that there is no document of that name to be uploaded.
you could either use set() or add() to add the document because it is not present.
noteUpdate = (id, noteObj) => {
firebase
.firestore()
.collection('notes')
.doc(id)
.update({
title: noteObj.title,
body: noteObj.body,
timestamp: firebase.firestore.FieldValue.serverTimestamp()
});
}
replace the above code with this
noteUpdate = (id, noteObj) => {
firebase
.firestore()
.collection('notes')
.doc(id)
.add({
title: noteObj.title,
body: noteObj.body,
timestamp: firebase.firestore.FieldValue.serverTimestamp()
});
}
or
noteUpdate = (id, noteObj) => {
firebase
.firestore()
.collection('notes')
.doc(id)
.set({
title: noteObj.title,
body: noteObj.body,
timestamp: firebase.firestore.FieldValue.serverTimestamp()
});
}
I was working with something like this only especially in Cloud Functions and while writing an endpoint for doing some operation I came across the below-quoted error.
I was trying to read a document in a collection and if it existed I was trying to write a new doc into another collection. So it was kind of a nested code.
A piece of my code.
const firstDocRef = db.collection('myFirstCollection').doc('myDocName');
const existDoc = firstDocRef.get()
.then((resDoc)=>{
if(resDoc.exists)
{
db.collection('mySecondCollection').add({
.
.
.
.
.
orderCreatedAt:Firestore.FieldValue.serverTimestamp()
})
.then((new_doc)=>{
return res.status(200);
// return 200 ok what we were trying to achieve has completed.
})
.catch(()=>{
console.log("Log, as write failed somehow");
return res.status(500);
// return a 500 internal server error occurred
});
}
else
{
console.log("My first condition wasn't met, so logged it");
return res.end();
// properly terminate the processing of request
}
});
/*.catch((err)=>{
console.log("Our first doc presence check couldn't complete and hence I arrived here, log it");
res.writeHead(500);
return res.end();
// again give back 500 to client
});*/
UnhandledPromiseRejectionWarning: ReferenceError: Firestore is not defined
UnhandledPromiseRejectionWarning: Unhandled promise rejection.
This error originated either by throwing inside of an async function without a catch block
Now I am also new to Firebase but I came across this and somehow solved it.
So I was not getting the above error if I was putting in a catch block in get() document.
Strange huh!
Removed the catch block by commenting it. Got this error.
Now, this is a haywire error, it says the catch is not there, but we did it on purpose.
So I began searching, came across this question here on stack overflow and saw it's still unanswered. Searched and read the documentation myself.
I would like to tell you that this isn't because of any Firestore Security Rules, or anything else. Because I came across some guesses around these notions too while searching for an answer.
The common thing we all are doing here is that we are trying to achieve the ServerTimeStamp at FireStore
I would like to bring your notice to my imports in my node cloud function code.
const functions = require('firebase-functions');
const express = require('express');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
So you see, I am using the new way of getting the permission to use Firestore because I am trying to establish a cloud function.
Now this is the documentation reference provided by Google: Click here!
The right syntax proposed by above API reference is
Firestore.FieldValue.serverTimestamp()
It is the culprit, it isn't providing me any timestamp and if there is not a catch block unhandled promise error is occuring and no error is being shown while debugging, it just doesn't work.
I did this, Solution part:
Even after those imports in my Node Program, I imported this:
const {Firestore} = require('#google-cloud/firestore');
Now all I did was that I used the statement in the timestamp field as
Firestore.FieldValue.serverTimestamp()
Exactly as mentioned and even used a catch block just in case any other problem occurs while at production. That is using db constant to do all the Database Transactional Stuff and just for serverTimeStamp I have to bring in new import.
And it worked, I guess require('#google-cloud/firestore') statement imported as {FireStore} brings in all the things that are required for the FieldValue thing to use as a reference.
I hope it helps any new person looking for it and saves a lot of time which I wasted searching for a solution.
I have verified it by running the cloud function on firebase emulator.
You could simply do it like this
You
Get it
If it exsits: you update it
If it doesn't exist, you set it.
const docRef = this.db.collection("users_holdings").doc(userId);
docRef.get().subscribe((doc) => {
if (doc.exists) {
docRef.update({
stockHoldings: stockHoldings,
});
} else {
docRef.set({
stockHoldings: stockHoldings,
});
}
});

await/async: compiler/syntax issue with conditionnals

I am using async/await in a web app to query a DB and use results for other queries.
I have this function:
exports.getByUserAndPurposeForService = async (req,res,next) =>{
var serviceID = await Service.getIdByName(req.params.serviceName)
var user_id = await User.getIdByName(req.params.userID)
if(condition){...}
Await/async works great there but whet it gets to this point:
else {
var userName= **await** ID.getUserID(serviceID, req.params.userID)
user_id = **await** User.getIdByName(userName)
}
else{
res.send('Not Allowed')
}
}
})
those two 'await' create an error in the IDE :
'Parsing error : unexpected token ID'
I don't know why, I can use await on functions outside the conditional but not inside.
Thanks a lot for all the help, I found what the problem was :
I was awaiting these promises inside a .exec() function
Like this :
Model.findOne({..}).exec(function(err, result){
var user = await ...
})
You can't apparently mix chaining with async/await
Thanks for the help !
So I fixed it by using await on Model.findOne({..}).exec() and storing result in variable I could use after

Resources