Assigning a Date Object to update - javascript

I would like to know how to assign a date object in this scenario, I need to update lastUpdate, whenever user changes his details.
I also tried Object.assign(user.lastUpdated, new Date());
exports.edit = (req, res, next) => {
const userid = req.params.id;
const errorHandler = (error) => {
next(error);
};
const updateUser = (user) => {
Object.assign(user, req.body);
Object.assign(user.lastUpdated, new Date());// not working
user.lastUpdated= new Date(); //not able to save this in database
user.save().then(() => {
res.json({
uid: user.id,
username: user.username,
displayName: user.displayName,
password:user.password,
lastUpdated: user.lastUpdated// result should be last updated Date.
});
}).catch(errorHandler);
};
};

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object. ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign ).
But in your code Object.assign(user.lastUpdated, new Date()); what you are trying to do is join two values together. So it won't work.
Try like this : Object.assign( user, { lastUpdated : new Date() } );

Related

mongoose create function in not function error(sub document)

schema
const UserSchema = new mongoose.Schema({
...,
suported: [{name:String, id:String}],
suporting: [{name:String, id:String}]
},
{ timestamps: true });
Query
const requester = await User.findOne({ _id })
const suporter = await User.findOne({ _id: _idSuporter })
// Result ok
requester.suported.create(data); // causing error
suporter.suporting.create(data);
Error message: requester.suported.create is not a function.
Edited
Links to where you can see what I am expecting
https://mongoosejs.com/docs/subdocs.html#adding-subdocs-to-arrays
https://attacomsian.com/blog/mongoose-subdocuments
The error is happening because it is not possible to call the create function on the "supported" attribute of the User object. What you can do is create a static function that takes the data as a parameter and does something when the function is called, like this:
userSchema.statics.createSupported = function(data: any) {
// do something here..
}
userSchema.statics.createSupporting = function(data: any) {
// do something here..
}
And when you call the query:
const requester = await User.findOne({ _id })
const supporter = await User.findOne({ _id: _idSuporter })
// Result ok
User.createSupported(date)
User.createSupporting(data)

MongoDB best approach to only POST data if it doesn't exist in the db?

What would be the best approach to only POST data into MongoDB if it doesn't exist in the table? hash would be the unique field for searching, this field is also indexed.
router.post('/', async (req, res) => {
try{
var id = null
const keywords = await db.dbConn('kw_data');
await keywords.insertOne({
result: req.body,
added: new Date(),
modified: new Date(),
hash: req.body.hash
}).then(resp => {
id = resp.insertedId
})
var data = {}
data = await keywords.findOne({_id: id});
res.status(201).send(data);
}
catch(e) {
res.status(400).send(e);
res.status(404).send(e);
res.status(500).send(e);
}
})
You can use
await keywords.update(
<query>,
<update>,
{
upsert: <boolean>,
}
);
and set
upsert:true
So you are inserting data and database will itself know if data is created it will get updated and if it does not exist the database will create it for you
I think I have got it by just doing a check on the hash, but not sure if this is the best approach, correct me if I'm wrong...
router.post('/sug', async (req, res) => {
try{
var id = null
const keywords = await db.dbConn('kw_sug');
check = await keywords.findOne({hash: req.body.hash});
if(check === null){
await keywords.insertOne({
results: req.body,
added: new Date(),
modified: new Date(),
hash: req.body.hash
}).then(resp => {
id = resp.insertedId
})
var data = {}
data = await keywords.findOne({_id: id});
res.status(201).send(data);
}else{
res.status(201).send('duplicated');
}
}
catch(e) {
res.status(400).send(e);
res.status(404).send(e);
res.status(500).send(e);
}
})

MongoDB/Express: Why does Array.includes return false instead of true?

I'm working on an tiny app that allows user to participate in polls, but I'm having problems checking if the current user has already voted in the poll. Everything else works fine, save for the IIFE that checks for said condition, as seen in the code snippet included. Indeed, I'm getting false as opposed to true with the data I have i.e. I already seeded the DB with sample data, including a random poll that contains the array of IDs for users who've already voted. I tried testing one ID against said array, which returns false as opposed to the expected true. What gives?
Below are the relevant snippets.
Model
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
const ChoiceSchema = new Schema({
name: { type: String },
votes: { type: Number }
});
const PollSchema = new Schema({
title: { type: String },
category: { type: String },
choices: [ChoiceSchema],
addedBy: { type: Schema.Types.ObjectId, ref: 'User' },
votedBy: [{ type: Schema.Types.ObjectId, ref: 'User' }]
});
const Poll = mongoose.model('Poll', PollSchema);
export default Poll;
Controllers
import Poll from '../models/poll';
export default {
fetchAllPolls: async (req, res) => {
/*...*/
},
fetchSpecificPoll: async (req, res) => {
/*...*/
},
voteInPoll: async (req, res) => {
const { category, pollId } = req.params;
const { name, choiceId, voterId } = req.body;
try {
const poll = await Poll.findById(pollId);
const choice = await poll.choices.id(choiceId);
const votedChoice = {
name,
votes: choice.votes + 1,
};
// Check if user has already voted in poll
const hasVoted = ((votersIds, id) => votersIds.includes(id))(
poll.votedBy,
voterId
);
if (!voterId) {
res
.status(400)
.json({ message: 'Sorry, you must be logged in to vote' });
} else if (voterId && hasVoted) {
res.status(400).json({ message: 'Sorry, you can only vote once' });
} else {
await choice.set(votedChoice);
await poll.votedBy.push(voterId);
poll.save();
res.status(200).json({
message: 'Thank you for voting. Find other polls at: ',
poll,
});
}
} catch (error) {
res.status(404).json({ error: error.message });
}
},
createNewPoll: async (req, res) => {
/*...*/
},
};
I think you are trying to compare ObjectId with String representing the mongo id.
This should work:
const hasVoted = ((votersIds, id) => votersIds.findIndex((item) => item.toString() === id) !== -1)(
poll.votedBy,
voterId
);
or
const hasVoted = ((votersIds, id) => votersIds.findIndex((item) => item.equals(new ObjectId(id))) !== -1)(
poll.votedBy,
voterId
);
EDIT:
As #JasonCust suggested, a simpler form should be:
const hasVoted = poll.votedBy.some(voter => voter.equals(voterId));
It is more than likely that poll.votedBy is not an array of ID strings. If you are using it as a reference field then it is an array of BSON objects which would fail using includes because it uses the sameValueZero algorithm to compare values. If that is true then you could either convert all of the IDs to strings first or you could use find and the equals methods to find a match.
Update: showing actual code example
Also, some would provide an easier method for returning a boolean value.
const hasVoted = poll.votedBy.some((voter) => voter.equals(voterId));

Push ObjectId in Mongoose

I'm using express, passport, and mongoose. I don't know why but the code below pushes same newTaxReturn._id twice into user.taxReturnIds field. If I remove user.save().catch(() => {}) line, it pushes the newTaxReturn._id correctly i.e. just once. The user argument is from passport.
Problem:
const createTaxReturn = ({ user }) => {
const newTaxReturn = new TaxReturn({ userId: user._id })
user.taxReturnIds.push(newTaxReturn._id)
user.save().catch(() => {})
return newTaxReturn.save().catch(() => {})
}
Schema:
const User = new mongoose.Schema({
taxReturnIds: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'TaxReturn',
}],
})
const TaxReturn = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
})
On your return you are also calling .save() thus the duplication and the single input when you remove
user.save().catch(() => {})
place your return in a .then or .catch to retrieve the response from mongo
user.save().catch(error => { if (error) return error })

Map function in NodeJS not working as expected

I am trying to migrate some data from an old MongoDB schema to a new one. All the schema stuff is working fine. What I cannot understand is why the old documents are not being converted before being saved as new documents. I am reading all the documents, using a map function to convert them to the new schema then saving them. But they are all failing validation because, it turns out, they haven't been modified to the new schema at all. Is this an async issue? Any clues would be great.
let User = require('./api/models/user.model');
let newUser;
let mapUsers = () => {
let makeUser = (u) => {
return {
firstName: u.first_name,
lastName: u.last_name,
avatarUrl: u.avatar_url,
email: u.email,
loginCount: u.login_count,
loginTime: u.login_time,
logoutTime: u.logout_time
}
};
h2User.find({}).limit(1).exec((err, users) => {
if (err) {
console.error(err);
} else {
users.map(user => {
newUser = new User(makeUser(user)); // like this doesn't work
newUser.save((err, nu) => {
if (err) {
console.log(err);
} else {
console.log(nu._id)
}
});
});
}
});
};
mapUsers();
You would have to convert the Mongo document into an object with new User(makeUser(user.toObject())).
As Mongoose returns a document, it will contain other attributes that may not be apparent. When you do console.log(user) it usually prints the output of toObject so it can get confusing.

Categories