Trying to send over routine data with api - javascript

I am building a fitness tracker through a class, it gives me built in tests to use as well. I am having an issue with passing this one in specific. I shortened the test specs for convenience.
Expected[{"activities": [{"activityId": 3,
Received {"publicRoutines": [{"activities": [{"activityId": 3,
1. Gets a list of public routines for a particular user.
2. Gets a list of all routines for the logged in user
I understand that the publicRoutines are sent in the res.send() but without the curly brackets, it sends over a failed test that is in my catch. Is there a way to send over both of these functions in my code to match the expected result?
usersRouter.get(`/:username/routines`,async(req,res) =>{
const username = req.params.username
try{
if(username){
const userRoutines = await getAllRoutinesByUser({username});
const publicRoutines = await getPublicRoutinesByUser({username})
console.log(publicRoutines, userRoutines)
res.send({publicRoutines, userRoutines})
}else{
return null;
}
}catch(error){
throw Error('Failed to get', error)
}
})

Yes, you can modify your code to send the expected result format by combining the two objects into a single object:
usersRouter.get(`/:username/routines`, async (req, res) => {
const username = req.params.username;
try {
if (username) {
const userRoutines = await getAllRoutinesByUser({ username });
const publicRoutines = await getPublicRoutinesByUser({ username });
console.log(publicRoutines, userRoutines);
res.send({ activities: [...publicRoutines.activities, ...userRoutines.activities] });
} else {
return null;
}
} catch (error) {
throw Error("Failed to get", error);
}
});
This way, you are combining the arrays of activities from both publicRoutines and userRoutines and returning it in the format that the test is expecting.

Related

Error while deleting a value of element in mongoDB array using filter function?

I tried to find the solutions over here but unable to get success while using $pull as the array values I have does not contain `mongo_id'.
So the scenario is that , I am trying to delete the specific comment of the particular user which I am passing through query params. M
My mongo data looks like this:
Now I am making API Delete request like this : http://localhost:8000/api/articles/learn-react/delete-comment?q=1 on my localhost .
ANd finally my code looks like this:
import express from "express";
import bodyParser from "body-parser";
import { MongoClient } from "MongoDB";
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect(
"mongodb://localhost:27017",
{ useNewUrlParser: true },
{ useUnifiedTopology: true }
);
const db = client.db("my-blog");
await operations(db);
client.close();
} catch (error) {
res.status(500).json({ message: "Error connecting to db", error });
}
};
app.delete("/api/articles/:name/delete-comment", (req, res) => {
const articleName = req.params.name;
const commentIndex = req.query.q;
withDB(async(db) => {
try{
const articleInfo = await db.collection('articles').findOne({name:articleName});
let articleAllComment = articleInfo.comments;
console.log("before =",articleAllComment)
const commentToBeDeleted = articleInfo.comments[commentIndex];
//console.log(commentToBeDeleted)
// articleAllComment.update({
// $pull: { 'comments':{username: commentToBeDeleted.username }}
// });
articleAllComment = articleAllComment.filter( (item) => item != commentToBeDeleted );
await articleAllComment.save();
console.log("after - ",articleAllComment);
//yaha per index chahiye per kaise milega pta nhi?
//articleInfo.comments = gives artcle comment
res.status(200).send(articleAllComment);
}
catch(err)
{
res.status(500).send("Error occurred")
}
},res);
});
I have used the filter function but it is not showing any error in terminal but also getting 500 status at postman.
Unable to figure out the error?
I believe you'll find a good answer here:
https://stackoverflow.com/a/4588909/9951599
Something to consider...
You can use MongoDB's built-in projection methods to simplify your code.
https://docs.mongodb.com/manual/reference/operator/projection/positional/#mongodb-projection-proj.-
By assigning a "unique ID" to each of your comments, you can find/modify the comment quickly using an update command instead of pulling out the comment by order in the array. This is more efficient, and much simpler. Plus, multiple read/writes at once won't interfere with this logic during busy times, ensuring that you're always deleting the right comment.
Solution #1: The recommended way, with atomic operators
Here is how you can let MongoDB pull it for you if you give each of your comments an ID.
await db.collection('articles').updateOne({ name:articleName },
{
$pull:{ "comments.id":commentID }
});
// Or
await db.collection('articles').updateOne({ name:articleName, "comments.id":commentID },
{
$unset:{ "comments.$":0 }
});
Solution #2 - Not recommended
Alternatively, you could remove it by index:
// I'm using "3" here staticly, put the index of your comment there instead.
db.collection('articles').updateOne({ name:articleName }, {
$unset : { "comments.3":0 }
})
I do not know why your filter is erroring, but I would recommend bypassing the filter altogether and try to utilize MongoDB's atomic system for you.

Retrieve an array from a Firestore document and store it to Node.Js then use it as tokens to send notifications

I've been trying to figure this out for hours and I just can't. I'm still a beginner with Node.js and Firebase. I need your help to be able to retrieve the tokens array in my "userdata" collection to Node.js and be able to use it to send notifications in the Cloud Function. So far this is what I've been working on. Here is what my database looks like:
The receiverId is gathered from when I have an onCreate function whenever a user sends a new message. Then I used it to access the userdata of a specific user which uses the receiverId as their uid.
In the cloud function, I was able to start the function and retrieve the receiverId and print the userToken[key]. However, when I try to push the token it doesnt go through and it results in an error that says that the token is empty. See the image:
Your help would mean a lot. Thank you!
newData = snapshot.data();
console.log("Retrieving Receiver Id");
console.log(newData.receiverId); //uid of the user
const tokens = [];
const docRef = db.collection('userdata').doc(newData.receiverId);
docRef.get().then((doc) => {
if (doc.exists) {
console.log("DocRef exist");
const userToken = doc.data().tokens;
for(var key in userToken){
console.log(userToken[key]);
tokens.push(userToken[key]);
}
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch((error) => {
console.log("Error getting document:", error);
});
//Notification Payload
var payload = {
notification: {
title: newData.sendBy,
body: 'Sent you a message',
sound: 'default',
},
data: {
click_action : 'FLUTTER_NOTIFICATION_CLICK',
route: '/telconsultinbox',
}
};
console.log("Sending Notification now.");
console.log(tokens);
try{
//send to device
const response = await admin.messaging().sendToDevice(tokens, payload);
console.log('Notification sent successfully');
console.log(newData.sendBy);
}catch(err){
console.log(err);
}
I think you should avoid using for..in to iterate through an array (you can read more about it in this answer). Try one of these 2 options:
You could use forEach(), which is more elegant:
userToken.forEach((token) => {
console.log(token);
tokens.push(token);
});
for-of statement:
for(const token of userToken){
console.log(token);
tokens.push(token);
}
Also, I would consider renaming userToken to userTokens, since it should contain multiple values. Makes the code a bit more readable.

nodemailer verify is returning success even with bad credentials

so I am trying to create a gmail client as a learning project. I am using nodemailer module to verify credentials and send mails. My code is as follows
let data ;
req.setEncoding('utf8') ;
await req.on('data', (chunk) => {
data = query.parse(chunk) ;
});
const mailer = nodemailer.createTransport({service: 'gmail'}) ;
mailer.options.auth = await data ;
mailer.verify((err, suc) => {
if (mailer.options.auth === undefined) {
console.log("No Credentials") ;
}
else if (err) {
console.log("Error : ") ;
} else {
console.log("success") ;
}
}) ;
PS : the function wrapping it is a async arrow function
It is correctly logging "No Credentials" when the post data received from form is empty, It is logging "success" even if entered credentials are wrong. I hope for a solution soon, Thanks in advance.
I've tried it myself and I've came to these 2 conclusions :
I haven't found any way to re-set the auth property after having created the Mail object using createTransport() method. Maybe there is one, maybe not. You're gonna have to look into it.
The verify() method does not check if the auth object is defined but rather checks if the props that it contains are defined and valid
But here's what I did and that works :
// the function returns an object of type { user: string, pass: string }
const credentials = await getMyAuthData();
const config = {
service: 'Gmail',
auth: credentials
};
const mailer = nodemailer.createTransport(config);
mailer.verify((error, success) => {
if (error) throw error;
console.log(success);
});

Res value is null in an app.get call done from vue.js front-end to express back-end

I am calling this code from the front-end and confirmed that there is a proper db connection and that the Id value is properly passed, and that there is a corresponding value in the database, but for some reason, res is null. What am I missing?
app.get("/api/walletlogin/user/:userId", (req, res) => {
id = req.params.userId
var query = {_id: id}
db.collection("Users").findOne(query, (err, result) => {
if (result) {
console.log(result.userName)
} else {
console.log('No User')
}
})
Here is the front-end call:
axios.get('/api/walletlogin/user/' + accounts)
.then((response) => {
console.log('Logged in With ' + accounts)
router.push('/account')
})
.catch((errors) => {
console.log('Cannot log in')
})
}).catch((err) => {
console.log(err, 'err!!')
})
You could try to convert your id to an objectID.
var ObjectId = require('mongodb').ObjectId;
var id = ObjectId(req.params.userId);
to search by id, you must use the ObjectID class from the mongodb package. Here is an example invented by me, it does not reflect the real work, but I hope it will become clear on it:
const { ObjectID } = require('mongodb');
const id = '5ee4f69bfa0b960de8aec158'; // in your example is req.params.userId
db.collection('users').findOne({ _id: new ObjectID(id)}, (error, result) => {
if (error) {
throw error;
}
console.log(result);
})
I am adding the details of the issue initially encountered in case someone else would experience it in the future. The value that is passed from the front-end is a cryptocurrency address. For some reason, some of the characters passed were upper-case, while the same address had been stored in the database with these same characters as lower case. Thus, one needs to add code to make sure that the case of the letters found in the respective addresses is ignored.
J

Get the _id of inserted document in Mongo database in NodeJS

I use NodeJS to insert documents in MongoDB. Using collection.insert I can insert a document into database like in this code:
// ...
collection.insert(objectToInsert, function(err){
if (err) return;
// Object inserted successfully.
var objectId; // = ???
});
// ...
How can I get the _id of inserted object?
Is there any way to get the _id without getting latest object inserted _id?
Supposing that in same time a lot of people access the database, I can't be sure that the latest id is the id of object inserted.
A shorter way than using second parameter for the callback of collection.insert would be using objectToInsert._id that returns the _id (inside of the callback function, supposing it was a successful operation).
The Mongo driver for NodeJS appends the _id field to the original object reference, so it's easy to get the inserted id using the original object:
collection.insert(objectToInsert, function(err){
if (err) return;
// Object inserted successfully.
var objectId = objectToInsert._id; // this will return the id of object inserted
});
There is a second parameter for the callback for collection.insert that will return the doc or docs inserted, which should have _ids.
Try:
collection.insert(objectToInsert, function(err,docsInserted){
console.log(docsInserted);
});
and check the console to see what I mean.
As ktretyak said, to get inserted document's ID best way is to use insertedId property on result object. In my case result._id didn't work so I had to use following:
db.collection("collection-name")
.insertOne(document)
.then(result => {
console.log(result.insertedId);
})
.catch(err => {
// handle error
});
It's the same thing if you use callbacks.
I actually did a console.log() for the second parameter in the callback function for insert. There is actually a lot of information returned apart from the inserted object itself. So the code below explains how you can access it's id.
collection.insert(objToInsert, function (err, result){
if(err)console.log(err);
else {
console.log(result["ops"][0]["_id"]);
// The above statement will output the id of the
// inserted object
}
});
if you want to take "_id" use simpley
result.insertedId.toString()
// toString will convert from hex
Mongo sends the complete document as a callbackobject so you can simply get it from there only.
for example
collection.save(function(err,room){
var newRoomId = room._id;
});
You could use async functions to get _id field automatically without manipulating data object:
async function save() {
const data = {
name: "John"
}
await db.collection('users').insertOne(data)
return data
}
Returns (data object):
{
    _id: '5dbff150b407cc129ab571ca',
    name: 'John',
}
Now you can use insertOne method and in promise's result.insertedId
#JSideris, sample code for getting insertedId.
db.collection(COLLECTION).insertOne(data, (err, result) => {
if (err)
return err;
else
return result.insertedId;
});
Similar to other responses, you can grab the variable using async await, es6+ features.
const insertData = async (data) => {
const { ops } = await db.collection('collection').insertOne(data)
console.log(ops[0]._id)
}
Another way to do it in async function :
const express = require('express')
const path = require('path')
const db = require(path.join(__dirname, '../database/config')).db;
const router = express.Router()
// Create.R.U.D
router.post('/new-order', async function (req, res, next) {
// security check
if (Object.keys(req.body).length === 0) {
res.status(404).send({
msg: "Error",
code: 404
});
return;
}
try {
// operations
let orderNumber = await db.collection('orders').countDocuments()
let number = orderNumber + 1
let order = {
number: number,
customer: req.body.customer,
products: req.body.products,
totalProducts: req.body.totalProducts,
totalCost: req.body.totalCost,
type: req.body.type,
time: req.body.time,
date: req.body.date,
timeStamp: Date.now(),
}
if (req.body.direction) {
order.direction = req.body.direction
}
if (req.body.specialRequests) {
order.specialRequests = req.body.specialRequests
}
// Here newOrder will store some informations in result of this process.
// You can find the inserted id and some informations there too.
let newOrder = await db.collection('orders').insertOne({...order})
if (newOrder) {
// MARK: Server response
res.status(201).send({
msg: `Order N°${number} created : id[${newOrder.insertedId}]`,
code: 201
});
} else {
// MARK: Server response
res.status(404).send({
msg: `Order N°${number} not created`,
code: 404
});
}
} catch (e) {
print(e)
return
}
})
// C.Read.U.D
// C.R.Update.D
// C.R.U.Delete
module.exports = router;

Categories