How to implement Redis Cache with MongoDB? - mongodb

const redis = require('redis');
const getAsync = promisify(client.get).bind(client);
router.get('/get_all', async (req, res) => {
let language = req.query.language;
let data = '';
try {
data = await getAsync(language);
}
catch (err) {
console.log(err);
}
if (data) {
console.log('Data is received from Redis Cache!');
res.send(data);
}
else {
try {
const result = await Users.find({
language: language
});
client.setex(language, 86400, JSON.stringify(result));
res.send(result);
}
catch (err) {
console.log('ERROR');
console.log('MONGO DB RETURNED THE FOLLOWING ERROR');
console.log(err);
res.end();
}
}
}
This is how i have implemented redis cache with mongod db.
* Is this the right way to do the implementation?
If it is wrong, please tell me how to implement.
One problem which i am facing now is, if i add try and catch block to
const data = await getAsync(language);
I am getting error.
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error >originated either by throwing inside of an async function without a catch >block, or by rejecting a promise which was not handled with .catch(). >(rejection id: 2)
Editted the code with two try and catch blocks.
Is this good way to implement redis with mongo?

Related

Mongoose .find Query doesn't return collection data

I have the following code to get all the data from a collection:
app.get('/', (req, res) => {
Question.find({}, (err, found) => {
if (!err) {
console.log(found)
res.send(found);
} else {
console.log(err);
res.sendStatus("Some error occured!")
}
}).clone().catch(err => console.log("Error occured -- " + err));
});
Using debug, I'm seeing that I'm connected to my database and also that I'm sending the appropriate query:
Mongoose: TopicsDB.find({}, { projection: {} })
However, none of the data from the collection is being returned.
This is probably because you are not using async and await in your call to the database. Every call to the database is by default an asynchronous call and hence it needs to have async and await for it to work properly.
app.get('/', async (req, res) => {
await Question.find({}, (err, found) => {
if (!err) {
console.log(found)
res.send(found);
} else {
console.log(err);
res.sendStatus("Some error occured!")
}
}).clone().catch(err => console.log("Error occured -- " + err));
});
Try this. Hope it helps.

Cloud Functions: Mongoose aggregate search causing Error: Collection method aggregate is synchronous error

I am calling a Cloud Function call from my Flutter app when it starts. When I start from 'flutter run', my function call returns Error: Collection method aggregate is synchronous.
But, when I refresh the app, with command + r, then it returns the correct value.
app.dart
var gameFunction = await functions.httpsCallable('gameS').call({
'gamingId': 'afijeoaijosf'
});
f function index
export const gameS = functions.https.onCall(async (data, context) => {
try {
return await gameFunctionF(data, context);
} catch (err) {
const aa = err as functions.https.HttpsError;
throw new functions.https.HttpsError(aa.code, aa.message, aa.details);
}
});
f function gameFunctionF
export async function gameFunctionF(data: any, context: CallableContext) {
console.log(data);
try {
return await db
.aggregate([
{ $project: { game_profile: 1} },
])
.toArray();
} catch (err) {
console.log(`aaaa - err - ${err}`);
throw 'nooooo';
}
}
When I start the app, I get that Collection method aggregate is synchronous error. But then when I refresh the app with command + r, it returns the data that I want. No variable has been changed no nothing. var gameFunction runs when the app.dart is called.
I really don't get why it is happening since it only causes this error when I start from flutter run but it works fine when I just refresh the app.
I'd tried with my android phone that it causes the error when i open the app after I terminate the app as well.
As Mousumi suggested to look at, that link solved the problem for me.
const mongoConn = createConnection();
export const mongooooooo = mongoConn.openUri(
`uri`,
{
connectTimeoutMS: 30000,
}
);
This is how I changed from createConnection(uri). And then, you have to adjust the db function to
(await db)
.aggregate([
{ $project: { game_profile: 1} },
])
The error has been solved! Thank you to Mousumi!
UPDATE ---------
I had to add await in front of (await db) in order to get the promise result.
await (await db)
.aggregate([
{ $project: { game_profile: 1} },
])

async function returns Promise { <pending> }

I am trying to write a function that takes a URL and returns the engagement stats from Facebook Graph API against that URL. But I am facing trouble as my function is just giving me Promise { <pending> } as output.
Here is my code:
const getFacebookStats = async (link, ACCESS_TOKEN) => {
try {
const resp = await axios.get(
`https://graph.facebook.com/v12.0/?id=${link}&fields=engagement&access_token=${ACCESS_TOKEN}`
);
return resp;
} catch (err) {
// Handle Error Here
console.error(err);
}
};
Any help would be much appreciated.
Call your function like this:
getFacebookStats(link, ACCESS_TOKEN).then(response => {
console.log(response);
}).catch(error => {
console.error(error);
});
Or you could call it using await inside an async function.
Check this answer for a more detailed explaination of Promises in javascript.

Why are my tests occasionally passing and occasionally failing? (Jest, Mongoose, MongoDB)

I have a setup file for my tests that looks like this:
const mongoose = require('mongoose');
mongoose.set('useCreateIndex', true);
mongoose.promise = global.Promise;
async function removeAllCollections() {
const collections = Object.keys(mongoose.connection.collections);
for (const collectionName of collections) {
const collection = mongoose.connection.collections[collectionName];
await collection.deleteMany();
}
}
async function dropAllCollections() {
const collections = Object.keys(mongoose.connection.collections);
for (const collectionName of collections) {
const collection = mongoose.connection.collections[collectionName];
try {
await collection.drop();
} catch (error) {
// Sometimes this error happens, but you can safely ignore it
if (error.message === 'ns not found') return;
// This error occurs when you use it.todo. You can
// safely ignore this error too
if (error.message.includes('a background operation is currently running'))
return;
console.log(error.message);
}
}
}
export default function setupDB(databaseName) {
// Connect to Mongoose
beforeAll(async () => {
const url = `mongodb://127.0.0.1/${databaseName}`;
await mongoose.connect(
url,
{
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
},
err => {
if (err) {
console.error(err);
process.exit(1);
}
}
);
});
// Cleans up database between each test
afterEach(async () => {
await removeAllCollections();
});
// Disconnect Mongoose
afterAll(async () => {
await dropAllCollections();
await mongoose.connection.close();
});
}
I am then writing tests like this:
import User from 'db/models/User';
import setupDB from 'utils/setupDbForTesting';
setupDB('mongoose_bcrypt_test');
it('correctly hashes and salts passwords', async done => {
// create a user a new user
const newUser = new User({
username: 'jmar777',
password: 'Password123'
});
await newUser.save(function (err) {
if (err) {
console.log(err);
}
});
const user = await User.findOne({ username: 'jmar777' });
user.comparePassword('Password123', function (err, isMatch) {
if (err) throw err;
expect(isMatch).toBeTruthy();
});
user.comparePassword('123Password', function (err, isMatch) {
if (err) throw err;
expect(isMatch).toBeFalsy();
});
done();
});
However, every other time I run these tests, they pass (or fail) so for every time T that the tests pass, T + 1 they will fail. My question is - why?
The tests fail because user (in the callback for User.findOne) returns null, even though the user has been saved.
I think the issue lies in the tearing down of the database, but I really can't see any problems. Any help would be appreciated, thanks.

MongoDB issue with saving value returned from findByID

I have an issue with function which update password. What I would like to have is a function which will update logged user data.
export const updateMe = async (req, res, next) => {
if (!req) {
res.status(400).end()
}
try {
const updatedDoc = await User.findById(req.user._id, function(err, doc) {
if (err) return next(err)
doc.password = req.body.password
doc.save()
})
.lean()
.exec()
res.status(200).json({ data: updatedDoc })
} catch (e) {
console.log(e)
res.status(400).end()
}
}
I have written middleware which will hash password before it will be saved.
userSchema.pre('save', function(next) {
if (!this.isModified('password')) {
return next()
}
bcrypt.hash(this.password, 8, (err, hash) => {
if (err) {
return next(err)
}
this.password = hash
next()
})
})
I do not know why error is always reciving with message "doc.save() is not a funcition"
You are mixing promise and await code, also doc.save() returns a promise so you need to await it.
( I assume you are already setting req.user._id in a middleware, and it is not null.)
So your method must be like this if async/await is used:
export const updateMe = async (req, res, next) => {
if (!req.body.password) {
return res.status(400).send("Password is required");
}
try {
let updatedDoc = await User.findById(req.user._id);
updatedDoc.password = req.body.password;
updatedDoc = await updatedDoc.save();
res.status(200).json({ data: updatedDoc });
} catch (e) {
console.log(e);
res.status(400);
}
};