Mongoose: updating new values only if not null - javascript

I already got another solution but cannot understand why mine doesn't work.
I tried to use $set: here but it didn't help. objForUpdate do return "name, lastname" when i print. If i replace {objForUpdate} with {name, lastname} - update works. But I cannot pass the parameters in variable.
//Route to UPDATE user
async updateUser(req, res) {
let { _id, type, name, lastname } = req.body;
try {
let objForUpdate = "";
for (var key in req.body) {
if (req.body.hasOwnProperty(key) && req.body.key !== null && req.body[key] !== "" && key !== '_id') {
console.log("this is key: " + key + ", and this is value req.body[key]: " + req.body[key]);
objForUpdate += key + ", ";
}
}
objForUpdate = objForUpdate.slice(0, -2);
const updated = await Users.updateOne({ _id }, {objForUpdate});
res.send({ updated });
} catch (error) {
res.send({ error });
}
}

If you would debug the code, you'll get it.
Lets say the req.body looks like { name: "foo", lastname: "bar" type: "2", _id: 1} and by the end of the for-loop and the slice op the objForUpdate would be "name, lastname, type" which is a string.
Now when you pass this string to the updateOne op, this part {objForUpdate} will get converted to { objForUpdate: "name, lastname, type" } (a conversion of identifier as key and its defined value as the value of that key).
And that update object is incorrect even with $set operator.
If i replace {objForUpdate} with {name, lastname} - update works. Why?
Because in this case with Object destructuring you unpacked the object as independent variables (name, lastname ...) with values. In this case the {objForUpdate} when passed would become {"name":"foo", "lastname":"bar", "type":"2"} which is correct as update object.

Related

Best way to update value of an object inside mongodb object

This is how I store each element in my mongodb collection.
{
_id: 'iTIBHxAb8',
title: 'happy birthday',
votesObject: { happy: 0, birthday: 0 }
}
I made a very dirty work around which I am not at all proud of which is this...
//queryObject= {id,chosenvalue};
let queryObject = req.query;
let id = Object.keys(queryObject)[0];
let chosenValue = queryObject[id];
db.collection("voting")
.find({ _id: id })
.toArray((err, data) => {
let { votesObject } = data[0];
votesObject[chosenValue] += 1;
data[0].votesObject = votesObject;
db.collection("voting").replaceOne({ _id: id }, data[0]);
res.redirect("/polls?id=" + id);
});
So basically what this does is It gets the chosen value which may be "happy" or the "birthday" from the above example.
Finding the complete object from the collection which matches the id.
Incrementing the chosen value from the found object.
Using replaceOne() to replace the previous object with the newly changed object.
I am incrementing the value inside chosen value by one everytime this piece of code executes.
This works perfectly fine but I want to know if there is any way to directly update the chosen value without all this mess. I could not find a way to do it else where.
you can use mongoose findOneAndUpdate
It will be something like
const updateKey = "votesObject.$."+ chosenValue
let incQuery = {}
incQuery[updateKey] = 1
Model.findOneAndUpdate(
{ _id: id },
{ $inc: incQuery },
{ new : false },
callback
)
You can use $inc operator.
Try something like this:
db.collection.update({
"_id": id
},
{
"$inc": {
"votesObject.birthday": 1
}
})
This query will increment your field birthday in one.
Check mongo playground exaxmple here

how to save objects from a JSON in different documents with mongoose?

Well I have the following doubt. I have the following:
JSON
[
{"name": "juan", "age": 10}
{"name": "pedro", "age": 15}
{"name": "diego", "age": 9}
]
User Schema
_group:{
type: mongoose.Schema.Types.ObjectId,
ref: 'Group'
},
name: {
type: String
},
age: {
type: Number
}
And I need to save or update this data in different docs with nodejs/mongoose. I planned to do the following
var data = JSON.parse(json)
for (var i = data.length - 1; i >= 0; i--) {
var name = data[i].name;
var age = data[i].age;
User.find({'name': par, '_group': group_id}, (err, user)=>{
if(err)
next(err);
// if it does not exist, create new doc
if(_.isEmpty(doc)){
var newuser = new User;
newuser.name = name;
newuser.age = age;
newuser.save((err, saved)=>{
})
}// if it exists, update it
else if(!_.isEmpty(doc)){
user.age = age;
user.save((err, saved)=>{
})
}
})
}
as you will see, the variables age and name within User.find remain undefined, so this does not work for me.
First of all, is it the right way to save this data? If so, how could I can use the for cycle variables (name and age) within User.find? If not, what do you recommend me to do?
Thanks,
Eduardo
NodeJS, ExpressJS, Mongoose
There is one more issue which I think you are facing that you are calling a method inside a loop and it takes a call-back, so it doesn't wait here for coming back and move to second iteration, so you might face undefined and some un-expected behavior.
I suggest you should use async/await
let user = await User.findOneAndUpdate({'name': par, '_group': group_id}, { name, age }, { upsert: true })
If you parsed given JSON well and assigned values to name and age, they are not undefined within User.find scope.
Did you checked those variables?
var name = data[i].name;
var age = data[i].age;
You can use mongoose findOneAndUpdate with the option { upsert: true }.
This tries to update an object in the DB and, if the object is not found, it creates it. So:
for (var i = data.length - 1; i >= 0; i--) {
var name = data[i].name;
var age = data[i].age;
User.findOneAndUpdate({'name': par, '_group': group_id}, { name, age }, { upsert: true, new: true, lean: true }, (err, updated) => {
if(err) console.log(err);
else console.log(updated);
})
}
The option new tells to return the updated object and the option lean tells to return a plain JSON, instead of Mongoose document object (the same as calling doc.toJson())
Using the upsert option, you can use findOneAndUpdate() as a find-and-upsert operation. An upsert behaves like a normal findOneAndUpdate() if it finds a document that matches filter. But, if no document matches filter, MongoDB will insert one by combining filter and update as shown below.
data.forEach( user => {
User.findOneAndUpdate({'name': user.name , '_group': group_id}, user , {upsert: true, new: true}, (err, data) => {
if(err) console.log(err);
console.log(data);
})
})

React, Firebase: Access values of JSON and also get key value

I am beginner working with firebase, react. I am able to get the required data from firebase based on userEmail. But I am very confused in accessing the data.
firebase.database().ref('/users').orderByChild('email').equalTo(userEmail).on('value', data => {
console.log('data: ', data);
})
I get the following output:
data: Object {
"-Lhdfgkjd6fn3AA-": Object {
"email": "t5#gmail.com",
"favQuote": "this is it",
"firstName": "t5",
"lastName": "l5",
},
}
Please help me how to access all values ("-Lhdfgkjd6fn3AA-" , firstname, lastname, email and favQuote) into variables like: data.firstName, data.lastName, data.key, etc . Thank you.
let data = {
"-Lhdfgkjd6fn3AA-": {
"email": "t5#gmail.com",
"favQuote": "this is it",
"firstName": "t5",
"lastName": "l5",
},
};
console.log(Object.keys(data))//returning an array of keys, in this case ["-Lhdfgkjd6fn3AA-"]
console.log(Object.keys(data)[0])
console.log(Object.values(data))//returning an array of values of property
console.log(Object.values(data)[0].email)
Do need to be careful that the above code with the hardcoded "0" as index because it assumed that your data object has only one key. If you have more key, you can't simply replace index either because property of object has no predictable sequence
It's really a JavaScript question. I had to figure this out too. ...this works.
var p;
var thisLine;
p = docu.data();
for (var k in p) {
if (p.hasOwnProperty(k)) {
if (isObject(p[k])) {
thisLine = p[k];
Object.keys(thisLine).forEach(function (key, index) {
console.log(key, index);
});
}
}
}
function isObject(obj) {
return obj === Object(obj);
}
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
So your first step is that you need to loop over the snapshot in your on() callback.
The second step is that you need to call Snapshot.val() to get the JSON data from the snapshot. From there you can get the individual properties.
firebase.database().ref('/users').orderByChild('email').equalTo(userEmail).on('value', snapshot => {
snapshot.forEach(userSnapshot => {
let data = userSnapshot.val();
console.log('data: ', data);
console.log(data.email, data.firstname);
});
})

How to get object field in Parse

Here is my query for a particular User:
var query = new Parse.Query("User");
query.get(userId, {
success: function(user) {
if (user === undefined){
response.success("No such user with this ID: " + userId)
}else{
response.success("successfull " + user.get('authData')); // authData is undefined whereas name, minAge and other primitive types are working fine
}
},
error: function() {
response.error("user lookup failed");
}
});
That user.get('authData') is returning undefined, however other primitive type fields such as name and age are working fine.
I am thinking it is because authData is object
How can I access it?

How to check email exists in firebase?

Hi I'm using firebase and javascript. I need to check for email id existing or not when new user signs up. This code works for user name or id, but shows error having email as record. I don't want to overwrite firebase unique key generation for each record.
var ref = new Firebase("https://kkk.firebaseio.com/");
var users = ref.child("users");
var userId = document.getElementById("email").value;
function checking()
{
checkIfUserExists(userId);
}
function userExistsCallback(userId, exists) {
if (exists) {
alert('user ' + userId + ' exists!');
} else {
alert('user ' + userId + ' does not exist!');
var check = users.push({ email: username});
}
}
function checkIfUserExists(userId) {
users.child(userId).once('value', function(snapshot) {
var exists = (snapshot.val() !== null);
userExistsCallback(userId, exists);
});
}
I'm getting this error when I enter email.
Error: Firebase.child failed: First argument was an invalid path: "anu#gmail.com". Paths must be non-empty strings and can't contain ".", "#", "$", "[", or "]"
I want my data in firebase to looks like this,
users:{
"ksjhfsjkbv67dsjhbcxcscdg":{
"email": "sdfs#gmail.com"
},
"kXdhbrurjw9974jjdsos_asd":{
"email": "anu#gmail.com"
},
...
Can someone help me?
If you're data in firebase has unique keys then it probably looks something like:
{
users:{
"dsjhfsjkbv67dsjhbcxcscdg":{
"email": "blah#whatever.com"
},
"sXdhbrurjw9974jjdsos_asd":{
"email": "anu#gmail.com"
},
...
}
}
the error your getting is because you cannot have illegal characters as the "keys" for your data so:
{
"anu#gmail.com": "email"
}
would not be acceptable hence the error:
Error: Firebase.child failed: First argument was an invalid path: "anu#gmail.com". Paths must be non-empty strings and can't contain ".", "#", "$", "[", or "]"
the "." is not allowed.
One way to check if your value exists if you do not know the unique key is to do something like:
users.once('value', function(snapshot) {
var exists = false;
snapshot.forEach(function(childSnapshot){
if(userId === childSnapshot.val().email){
exists = true;
}
})
userExistsCallback(userId, exists);
});
you can read more about the for each function here:
https://www.firebase.com/docs/web/api/datasnapshot/foreach.html
I don't think you have to check if the email already has an account because firebase can not create another account with the same email.

Categories

Resources