I'm trying to update value in mongoDB and it's not changing the value. I checked the values and they are ok and I checked the errors and everything looks good. what am I missing?
Mongo atlas
picture of my mongo values
type: Number,
default: 0
code :
// symbol = the symbol of the coin | ammount = the ammount of coin
// in this case : symbol = USDT | ammount = 3
const setCoin = async (symbol, ammount) => {
setError(false);
try {
setError(false);
const res = await axios.patch("http://localhost:3001/api/users/setCoin", {
email: user.email,
symbol, ammount
});
res.data && window.location.replace("/home");
console.log(error)
} catch (err) {
setError(true);
}
};
server side
//setCoin
router.route("/setCoin")
.patch(async (req, res,) => {
try {
const symbol = req.body.symbol;
const user = await User.findOneAndUpdate({ "email": req.body.email }, { $set: { symbol: req.body.ammount } }, { upsert: true });
console.log("succes to set coin");
} catch (err) {
res.status(500).json(User.symbol);
console.log(err)
}
});
So as I dont know how you defined your User model can you try the following:
const user = await User.findOneAndUpdate({ "email": req.body.email }, { $set: { [symbol]: req.body.ammount } }, { upsert: true });
Related
i'm trying to show a user specific data using req.session.user and pass the ID to the criteria i'm building. (every entry also has a user field so i can match) yet it does not work.
The Service :
async function query(filterBy) {
try {
const criteria = _buildCriteria(filterBy);
const collection = await dbService.getCollection('tab');
const tabs = await collection.find(criteria).toArray();
// const userTabs = await collection.find({ user: '62be030cb4de461a8462b863' }).toArray();
return tabs;
} catch (err) {
logger.error('Can not find tabs', err);
throw err;
}
}
The console.log('userId', userId) returns the Id I get from my controller
function _buildCriteria(filterBy) {
const criteria = {};
const { text, genre, userId } = filterBy;
console.log('userId', userId);
if (text) {
const txtCriteria = { $regex: text, $options: 'i' };
criteria.name = txtCriteria;
}
if (genre) {
criteria.genre = { $eq: genre };
}
if (userId) {
criteria.user = { $eq: userId };
}
return criteria;
}
The controller :
async function getTabs(req, res) {
try {
const userId = req?.session?.user?._id;
const filterBy = req.query;
const fitlerUpdated = { ...filterBy, id: userId };
const tabs = await tabService.query(fitlerUpdated);
res.json(tabs);
} catch (err) {
logger.error('Failed to get tabs', err);
res.status(500).send({ err: 'Failer ti get tabs' });
}
}
I tried using
const userTabs = await collection.find({ user: '62be030cb4de461a8462b863' }).toArray()
and it works yet it doens't work along with the criteria.
thanks for any help!
I have realize I accidentally passed the wrong key.
should have been id and not userId
I have one question about a problem that I'm not able to fix. I try to update push a string passed via Query in my mongoose collection.
My collection are like this:
{
"_id": {
"$oid": "6199288597e42bf84d017f9e"
},
"name": "Lisa",
"surname": "Bianchi",
"ID_school": "afbH598U3",
"classes": [
{
"class": "5A",
"activities": {
"in_progress": [],
"finisched": []
},
"_id": {
"$oid": "6199288597e42bf84d017f9f"
}
},
{
"class": "1A",
"activities": {
"in_progress": [],
"finisched": []
},
"_id": {
"$oid": "6199288597e42bf84d017fa0"
}
}
],
"email": "insegnante#a.com",
"__v": 0
}
and I try to push a string in in_progress array that match, for example, with class:"5A" using this way:
import db from "../models/index.js";
const Teacher = db.teacher
const updateActivity = (req, res) => {
const query = { _id: req.query.id};
const update = {$push:{'classes.$[group].activities.in_progress': req.query.data } };
const options = {arrayFilters: { 'group.class': req.query.class }};
Teacher.findOneAndUpdate(query, update, options).exec((err, data) => {
if (err) {
res.status(400).send({ message: err });
return;
} else {
res.status(200).send(data);
}
})
}
const API = {
updateActivity
}
export default API
The query works fine, but nothing was pushed. I tested whit Insomnia passing in the Query field
id = 6199288597e42bf84d017f9e;
class:'5A';
data:"pushed"
Any suggestion? Thanks!
try this way by passing classes.class in query and also change push to $push:{'classes.$.activities.in_progress': req.query.data }
const updateActivity = (req, res) => {
const query = { _id: req.query.id ,'classes.class': req.query.class};
const update = {$push:{'classes.$.activities.in_progress': req.query.data } };
Teacher.updateOne(query,update).exec((err, data) => {
if (err) {
res.status(400).send({ message: err });
return;
} else {
res.status(200).send(data);
}
})
}
There are two ways of doing this:
Option 1: arrayFilters - more flexible Docu
The option you are using.
You have a syntax error - arrayFilters should be an array of documents.
const updateActivity = (req, res) => {
const query = { _id: req.query.id };
const update = {
$push:{ 'classes.$[group].activities.in_progress': req.query.data }
};
// This MUST be an array of filter documents!
const options = { arrayFilters: [{ 'group.class': req.query.class }] };
Teacher
.findOneAndUpdate(query, update, options)
.exec((err, data) => {
if (err) {
res.status(400).send({ message: err });
return;
} else {
res.status(200).send(data);
}
});
}
Option 2: Via Query (as answered by #Saurabh Mistry)
Repeating his answer for completeness
By specifying a query that targets a particular element in an array within result documents.
const updateActivity = (req, res) => {
const query = {
_id: req.query.id,
'classes.class': req.query.data,
};
const update = {
$push:{ 'classes.$.activities.in_progress': req.query.data }
};
Teacher
.findOneAndUpdate(query, update, options)
.exec((err, data) => {
if (err) {
res.status(400).send({ message: err });
return;
} else {
res.status(200).send(data);
}
});
}
I'm currently working on a validation system using Node, Express and Mongoose and have stumbled into a bit of problem. In my Schema I have a verificationId associated with the user so that when they click the link emailed to them it can check to see if that verificationId is the same as the one in the database. All of that works fine, but I can't figure out how to delete the verificationId now that it's no longer needed.
Currently it's validating the user but not deleting verificationId. I've tried messing with the $pull method but I haven't had any success with it. Any help would be appreciated!
//User verification page
app.get("/verify/users/:verifiedId", (req, res) => {
const verifiedId = req.params.verifiedId;
//Check to see if the verificationHash the user was sent is the same as the one stored for them in the database
User.findOne({ verificationHash: verifiedId }, (err, result) => {
if (!err) {
console.log(verifiedId);
console.log(result);
const originalValue = { isVerified: false };
const newValue = { isVerified: true };
//Verify the user in the database
User.findOneAndUpdate(originalValue, newValue, (err) => {
if (!err) {
if (newValue) {
res.redirect("/success");
} else {
res.send(
"There was an error verifying your account. Please try again."
);
}
} else {
res.send(500, { error: err });
}
});
} else {
res.send(err);
console.log(err);
console.log(verifiedId);
}
//Delete the verificationHash from the user in the database
User.findOneAndUpdate(
{ verificationHash: verifiedId },
{ $pull: { verificationHash: { verificationHash: verifiedId } } },
{ new: true }
) });
});
I'm not very sure about this answer but try using the unset operator:
User.findOneAndUpdate(
{ verificationHash: verifiedId },
{ { $unset: {"verificationHash": ""} },
{ new: true }
)
or this may work ( setting the value to null )
User.findOneAndUpdate(
{ verificationHash: verifiedId },
{ verificationHash: null },
{ new: true }
)
I am new to firebase and would like to implement the ranking for the players stored in the rank table from firebase real-time db, see screenshot below:
I have also setup the rules for the index:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"TH": {
"rank": {
".indexOn" : ["balance", "w_rate","match"]
}
}
}
}
in my firebase function, I have a function as a post request to get the rank:
exports.getRank = functions.https.onRequest(async (req,res) => {
const user_id = req.query.id;
console.log(`user_id ${user_id} `);
const query = database().ref('TH/rank')
.orderByChild('balance')
.limitToLast(30)
query.once('value',function(snapshot) {
console.log('in side the usersRef');
console.log(`snapshot:${JSON.stringify(snapshot.val())}`);
let current_user_rank = 0;
if (user_id !== null) {
console.log(`user id ${user_id} isn't null`);
database().ref('TH/rank/').orderByChild('balance').once('value',function(all_snapshot){
let index = 0;
console.log(`user id ${user_id} all snapshot.`);
if (all_snapshot.child(`${user_id}`).exists()) {
console.log(`user id ${user_id} exists`);
const current_user_data = all_snapshot.child(`${user_id}`).val();
all_snapshot.forEach( child => {
index += 1;
console.log(child.key, child.val());
if(child.key === user_id) {
current_user_rank = all_snapshot.numChildren() - index;
}
});
res.json({
user: { id: user_id,
rank: current_user_rank,
data: current_user_data
},
rank: snapshot.val()
});
} else {
res.json({
user: { id: user_id,
rank: current_user_rank,
data: null
},
rank: snapshot.val()
});
}
}).catch();
} else {
res.json({
user: { id: user_id,
rank: current_user_rank,
data: null
},
rank: snapshot.val()
});
}
}).catch();
});
However, the result isn't correct, it seems the orderByChild doesn't work at all. Can someone help on this?
Thanks.
There are several problems with your Cloud Function:
You use async when declaring the callback but you never use await in the Cloud Function, in order to get the result of the asynchronous once() method.
Instead of using the callback "flavor" of the once() method (i.e. ref.once('value',function(snapshot) {..}), use the promise "flavor" (i.e., with await: await ref.once('value');).
The result is that you don't correctly manage the Cloud Function life cycle. For more details on how to do that correctly, I would suggest you watch the 3 videos about "JavaScript Promises" from the Firebase video series as well as read the following doc.
So the following should do the trick. (Note that I've just adapted it to correctly manage the life cycle, I've not tested the business logic).
exports.getRank = functions.https.onRequest(async (req, res) => {
try {
const user_id = req.query.id;
console.log(`user_id ${user_id} `);
let current_user_rank = 0;
if (user_id !== null) {
console.log(`user id ${user_id} isn't null`);
const baseQuery = database().ref('TH/rank/').orderByChild('balance');
const query = baseQuery.limitToLast(30);
const snapshot = await query.once('value');
console.log(`snapshot:${JSON.stringify(snapshot.val())}`);
const all_snapshot = await baseQuery.once('value');
let index = 0;
console.log(`user id ${user_id} all snapshot.`);
if (all_snapshot.child(`${user_id}`).exists()) {
console.log(`user id ${user_id} exists`);
const current_user_data = all_snapshot.child(`${user_id}`).val();
all_snapshot.forEach(child => {
index += 1;
console.log(child.key, child.val());
if (child.key === user_id) {
current_user_rank = all_snapshot.numChildren() - index;
}
});
res.json({
user: {
id: user_id,
rank: current_user_rank,
data: current_user_data
},
rank: snapshot.val()
});
} else {
res.json({
user: {
id: user_id,
rank: current_user_rank,
data: null
},
rank: snapshot.val()
});
}
} else {
res.json({
user: {
id: user_id,
rank: current_user_rank,
data: null
},
rank: snapshot.val()
});
}
} catch (error) {
console.log(error);
res.status(500).send(error);
}
});
Update following your comment:
You need to use forEach() in order to get the children correctly ordered, and not snapshot.val(). snapshot.val() displays the children according to their key, exactly like they are ordered in the DB. The following adaptation of the code in your comment works correctly:
exports.getSortedRank = functions.https.onRequest(async (req, res) => {
try {
const obj = {};
const baseQuery = admin.database().ref('TH/rank/').orderByChild('balance');
const query = baseQuery.limitToLast(10);
const snapshot = await query.once('value');
snapshot.forEach(childSnapshot => {
console.log(childSnapshot.val());
obj[childSnapshot.key] = childSnapshot.val()
});
res.json({ rank: obj });
} catch (error) { console.log(error); res.status(500).send(error); }
});
I am working on an application where I can save destinations to my Mongo DB. I would like to throw a custom error when trying to save a destination that already exsist in the DB. Mongoose prevents that from happening but I want clear and userfriendly error handling.
// post a new destination
router.post('/',
(req, res) => {
const newCity = new cityModel(
{
name: req.body.name,
country: req.body.country
}
)
newCity.save()
.then(city => {
res.send(city)
})
.catch(err => {
res.status(500).send('Server error')
})
});
Before saving a new destination, you can check if there is document already using findOne method, and if it exists you can return a custom error.
router.post("/", async (req, res) => {
const { name, country } = req.body;
try {
const existingDestination = await cityModel.findOne({name,country});
if (existingDestination) {
return res.status(400).send("Destionation already exists");
}
let newCity = new cityModel({ name, country });
newCity = await newCity.save();
res.send(city);
} catch (err) {
console.log(err);
res.status(500).send("Server error");
}
});
Note that I guessed the duplication occurs when the same country and name exist. If it is not what you want, you can change the query in findOne.
Since you've created unique index, When you try to write duplicate then the result would be :
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error index: test.collection.$a.b_1 dup key: { : null }"
}
})
Your code :
Constants File :
module.exports = {
DUPLICATE_DESTINATION_MSG: 'Destionation values already exists',
DUPLICATE_DESTINATION_CODE: 4000
}
Code :
//post a new destination
const constants = require('path to constants File');
router.post('/',
(req, res) => {
const newCity = new cityModel(
{
name: req.body.name,
country: req.body.country
}
)
try {
let city = await newCity.save();
res.send(city)
} catch (error) {
if (error.code == 11000) res.status(400).send(`Destination - ${req.body.name} with country ${req.body.country} already exists in system`);
/* In case if your front end reads your error code &
it has it's own set of custom business relates messages then form a response object with code/message & send it.
if (error.code == 11000) {
let respObj = {
code: constants.DUPLICATE_DESTINATION_CODE,
message: constants.DUPLICATE_DESTINATION_MSG
}
res.status(400).send(respObj);
} */
}
res.status(500).send('Server error');
})