Data is mutated but not updated in the database - node.js

I have a sever connected to a mongodb database. When I add a first level data and then save that, it works.
For example :
// this works fine
router.post('/user/addsomedata', async (req,res)=>{
try {
const user = await User.findOne({email : req.body.email})
user.username = req.body.username
await user.save()
res.send()
} catch(e) {
res.status(404).send(e)
}
})
BUT if I try to save the object with deeper level data, it's not getting saved. I guess the update is not detected and hence the user didn't get replaced.
Example :
router.post('/user/addtask', auth ,async (req,res)=>{
const task = new Task({
name : req.body.name,
timing : new Date(),
state : false,
})
try {
const day = await req.user.days.find((day)=> day.day == req.body.day)
// day is found with no problem
req.user.days[req.user.days.indexOf(day)].tasks.push(task)
// console.log(req.user) returns exactly the expected results
await req.user.save(function(error,res){
console.log(res)
// console.log(res) returns exactly the expected results with the data filled
// and the tasks array is populated
// but on the database there is nothing
})
res.status(201).send(req.user)
} catch(e) {
res.status(400).send(e)
}
})
So I get the tasks array populated on the console even after the save callback but nothing on the db image showing empty tasks array

You're working on the user from the request, while you should first find the user from the DB like in your first example (User.findOne) and then update and save that model.

Use .lean() with your find queries whenever you are about to update the results returned by mongoose. Mongoose by default return instance objects which are immutable by nature. lean() method with find returns normal js objects which can be modified/updated.
eg. of using lean()
const user = await User.findOne({email : req.body.email}).lean();
You can read more about lean here
Hope this helps :)

Related

MongoDB: findOne not working as expected?

I'm creating an API to my database of coins and I don't want to add duplicate coins to my database so I've created this line of code in my function
const addCoin = async (req, res) => {
const { coinId, seconds, bidAmount } = req.body;
console.log(coinId);
const coinExists = await Coin.findOne({ coinId });
console.log(coinExists);
if (coinExists) {
res.status(400).send({ message: 'Coin Exists Bad Request' }); // bad request
throw new Error('Coin already exists');
}
In my Postman I am inputting a different coinId in the request body and I am getting the error that Coin Exists?
Is findOne here not working as expected?
Confused.
Thanks
Ahh after some documentation reading
I have to specify which property in the Coin Model I want it to find specifically
so in this case
I did
Coin.find({ itemId: coinId})
Since in my model its defined as itemId but user input is coinId

Remove object by id from an array in mongoose

So this seems pretty straightforward but I cant seem to get it to work.I have a document in mongodb and i m using mongoose All i need to do is find user by id, get the document and delete one specified object from an array of objects. Here is the Structure:
report:[
{
asset_report_id:234,
name:'somethign,
},
{
asset_report_id:23,
name:'somethign,
},
{
asset_report_id:111,
name:'somethign,
}
]
I tried this :
User.findOne({_id: request.decodedTokenData.userId})
.exec()
.then(user=>{
const result = user.reports.find( ({ asset_report_id }) => asset_report_id === assetID );
console.log('IN FIND',result);
})
.catch(err=>console.log(err))
Now i do get the result which is great and i can delete but isn't there a method to do it with mongoose directly? More alongthe lines of plain mongo version of :
db.removeObject.update( {'_id':ObjectId("5c6ea036a0c51185aefbd14f")},
{$pull:{"reports":{"asset_report_id":234}}},false,true);
So the correct solution is:
await User.updateOne( {'_id':ObjectId("5c6ea036a0c51185aefbd14f")},
{$pull:{"report":{"asset_report_id":234}}},false,true)
since the data model contains "report" array

Sequelize - Creating Multiple Tables Using Id of First Table Created

I'm doing a project using Express, & Sequelize and have run into an issue:
I'm trying to create an api route that, on a button click, will create a row in my 'member' & 'memberinstrument' tables. Those tables have an association in my models that: member 'hasMany' memberinstruments & memberinstruments 'belongsTo' member.
This is what I have right now:
router.post("/api/individual/signup", async (req, res) => {
try {
const member = await db.Member.create({
memberName: req.body.memberName,
location: `${req.body.city}, ${req.body.state}`,
profilePicture: req.body.profilePicture,
UserId: req.user.id
})
const memberInstrument = await db.MemberInstrument.create({
instrument: req.body.instrument,
MemberId: member.id
});
res.json({ member, memberInstrument });
} catch (error) {
console.log(error.message);
res.status(500).send('Sever Error');
}
})
I'm testing it out in postman and it simply says I have a 'server error' (which doesn't happen if I delete the whole memberInstrument posting section) and in node I get "Cannot read property 'id' of undefined". I know it must have something to do with the timing of trying to create member, and then trying to get that member id for memberinstrument, but I can't figure out how to resolve this.
Any help would be much appreciated!
(edit:
I commented out both UserId & MemberId and it successfully posts.
uncommenting just UserId creates the same error:
UserId is a nullable field so I don't know why it's doing a server error if I don't define it (or maybe I have to define it as null but I do not know how to do that in postman since it's coming from .user instead of .body
uncommenting just MemberId creates the same error)
Since I'm doing this in Postman, and don't know how to send a req.body with that, I was getting that id error. I changed req.user.id to req.body.id which will be populated with information from a front end state and it is now working correctly.
I think it's unnecessary for you to include all the fields in your .create()
try this
router.post("/api/individual/signup", async (req, res) => {
try {
const data = req.body;
const member = await db.Member.create(data);
const [registration, created] = member;
if(created){
//insert more of your code here on creating **MemberInstrument**, this is just a sample.
await db.MemberInstrument.create(registration.member_id);
}
res.json({
registration,
created
});
} catch (error) {
console.log(error);
res.status(500);
}
}
On your postman request, you will input the body or fields in json format, except the ID, IDs should not be included on the postman body.

How to update/insert an other document in cloud firestore on receiving a create event for a collection using functions

Let us assume that we have two collections say "users" and "usersList"
Upon creating a new user document in users collection with following object
{username: Suren, age:31}
The function should read the above data and update other collection i.e. "usersList" with the username alone like below
{username: Suren}
Let me know the possibility
The code I have tried is
exports.userCreated =
functions.firestore.document('users/{userId}').onCreate((event) => {
const post = event.data.data();
return event.data.ref.set(post, {merge: true});
})
I have done it using below code
exports.userCreated = functions.firestore.document('users/{userId}')
.onCreate((event) => {
const firestore = admin.firestore()
return firestore.collection('usersList').doc('yourDocID').update({
name:'username',
}).then(() => {
// Document updated successfully.
console.log("Doc updated successfully");
});
})
If all you want to do is strip the age property from the document, you can do it like this:
exports.userCreated = functions.firestore.document('users/{userId}').onCreate((event) => {
const post = event.data.data();
delete post.age;
return event.data.ref.set(post);
})

How to query for an array of users in my users collection in mongodb using mongoose?

I have a collection of some users (along with their contact numbers) registered in my node and mongodb app.
Now I have an array of contact numbers. I want to get an intersection of this array and the users in my app. How to do it, since I cannot take each number and check for it's existence in the database. Any help/link would be helpful. Thanks in advance.
You can use the $in operator. It would really help if you at least provided some code, like your schemas, previous attempts etc.
Here is an example of how to do ii assuming you are using mongoose, and have a user schema with a number property and an array of numbers.
User.find({ number: { $in: numbers } })
.then(function (docs) {
// do something with docs here;
})
.catch(handleErr);
This can be done simply using promises. I am assuming you have an array of contact numbers and a collection Users which has field contact number. The below function will get you the list of all the Users with contact numbers listed in the array. I am assuming that the User model is available and the contact array is being passed as a function argument. Basically this function will loop through the contact list array and find any user with that contact no in the user collection and return a promise. All the promises are being pushed into an array and the promise will be resolved only when all the async operations have completed resulting in either success or error.
// import User from User-model-defition
function getUsersByContact(contactArr) {
return new Promise((resolve, reject) => {
const data = [];
const errors = [];
contactArr.map(id => {
User.findOne({ contact_no : id })
.then(response => {
if (response.user) { //checking if the response actually contains a user object
data.push(response.user);
} else {
errors.push(response.error);
}
if (contactArr.length === data.length + errors.length) {
//this makes sure that the promise will be resolved only when all the promises have been resolved
resolve({ data, errors });
}
})
.catch(error => reject(error));
})
})
}

Resources