Getting [Function: toBSON] and {} when console logging an array - mongodb

I am trying to figure out why I am getting
console.log(removedEvent.invitees[i]) result:
luke231#gmail.com
yoda231#gmail.com
[Function: toBSON]
{}
... The rest is information about removedEvent itself
But if I console log before my for loop I get the following... console.log(removedEvent.invitees);
["luke231#gmail.com","yoda231#gmail.com"]
Here is my code (disregard res headers, I know.):
router.delete(
"/remove/:event_id",
passport.authenticate("jwt", { session: false }),
(req, res) => {
Event.findOneAndRemove({ _id: req.params.event_id }).then(removedEvent => {
console.log(removedEvent.invitees);
for (let i in removedEvent.invitees) {
console.log(removedEvent.invitees[i]);
User.findOne({ email: removedEvent.invitees[i] })
.then(user => {
res.json(user);
})
.catch(err => res.json({ err }));
}
});
}
This is throwing everything off because of me looping through my User.findOne

I didn't figure out why I was getting that output when I console.log'd, but I used forEach() instead of the for loop and it works as expected.

Related

"[Function: Error Ctor]" error in console

the first console log is getting logged but the second one isn't
and the catch is catching an error which I do not understand ...
this is my route:
router.post("/buy", JwtAuthenticateToken, async (req, res, next) => {
try {
const entry = new PositionModel(req.body)
console.log("new", entry)
const result = await entry.save()
console.log("saved", result)
} catch (error) {
console.log(error)
next(error)
}
})
this is what gets printed in the console:
new {
_id: 6125514a26fb7d06603b1a5a,
stock: 'Apple Inc',
ticker: 'AAPL',
purchasePrice: 149.62,
shares: 1,
owner: 6124e2a70d195a05f4e480cd
}
[Function: ErrorCtor]
I was passing an error to an error creator in my .post("validate")
probably the dumbest 5 lines of code I have ever written.
post("validate", (error, doc, next) => {
if (error) {
const err = createError(400, error)
next(err)
} else {
next(error)
}
})

Unable to return value from nano.view callback

Unable to store value outside of callback scope
I have tried declaring an array, an object and an empty variable outside of the callback scope and nothing is working.
router.post('/login', async (req, res, next) => {
try {
const user = await users.view('viewEmailandPassword', 'email', {keys: [`${req.body.email}`], include_docs: true},
function(err, body) {
if (!err) {
body.rows.forEach(function(doc) {
console.log(doc.value)
// return doc.value
});
}
});
console.log(user) <--- nothing is returned
}
catch(err){
next(err)
console.err(err, "this is the error")
}
})
I get an output of "undefined"
The problem here is that you're trying to use callback + promises. You need to either choose one or the other.
Here's the implementation using Promises (with async/await)
router.post('/login', async (req, res, next) => {
try {
const body = await users.view('viewEmailandPassword', 'email', {keys: [`${req.body.email}`], include_docs: true});
// Prints all the row values
body.rows.forEach(doc => console.log(doc.value));
// Let's say you want the first row
if(body.rows.length > 0){
console.log(body.rows[0].value);
} else {
console.log("Not value returned from the view");
}
}
catch(err){
next(err)
console.err(err, "this is the error")
}
})

How to pass id to its associated records with Sequelize

I'm building an app with Express on backend, Postgres for db and Sequelize for ORM.
I have 3 associated models:
Post
Event
Publishing, belongs to Post, belongs to Event
When I publish my Post, I update its state to 2, I need to create an Event and Publishing. Publishing will have the postId and eventId, among other things that I'm passing with a query. I tried the following code, it changes the state of the Post, creates an Event and Publishing, but they are not related to each other.
publishPost(req) {
return new Promise((resolve, reject) => {
async.parallel({
changeState: (callback) => {
Post.findAll({
where: { id: req.query.post_id },
attributes: ['id', 'state']
})
.then((updateState) => {
updateState.forEach((postState) => {
postState.updateAttributes({ state: 2 });
});
})
.then((updatedState) => {
callback(null, updatedState);
});
},
createEvent: (callback) => {
Event.create({
instructions: req.query.instructions,
})
.then((createdEvent) => {
callback(null, createdEvent);
});
},
createPublishing: (callback) => {
Publishing.create({
start_date: req.query.startDate,
end_date: req.query.endDate,
})
.then((createdPublishing) => {
callback(null, createdPublishing);
});
}
}, (error, result) => {
resolve(result);
});
});
}
How can I pass the IDs of the two records to the third model?
There are several problems with your implementation!
First of all, your promise never rejects.
Despite of that, you don't actually need to create a promise or use async for this, neither do you want them to run in parallel: If creating a Publishing record needs information about the Event, then you'd want to create first the event, so that you have its id, THEN pass it in the input for the publishing.
Another important thing, take a look at this piece of code:
.then((updateState) => {
updateState.forEach((postState) => {
postState.updateAttributes({ state: 2 });
});
})
.then((updatedState) => {
callback(null, updatedState);
});
Inside the first then, you are making multiple updates, which are promises. They will be dispatched and you never get their values back. Let me explain:
Think if you have just one update to make. It would be like this:
.then((updateStates) => {
return updateStates[0].updateAttributes({ state: 2 });
})
See, we are returning a promise (in this case the update), so the next then will only be called when the update resolves.
If we do this:
.then((updateStates) => {
updateStates[0].updateAttributes({ state: 2 });
})
It will dispatch the update (which takes time) but because you didn't return it, it will pass through and return nothing. Check this out:
var promise1 = new Promise(function(resolve, reject) {
setTimeout(function(){
resolve('foo')
}, 2);
});
var promise2 = new Promise(function(resolve, reject) {
setTimeout(function(){
resolve('foo2')
}, 2);
});
promise1
.then(function(result){
promise2
})
.then(function(result){
console.log(result) //will print undefined
})
promise1
.then(function(result){
return promise2
})
.then(function(result){
console.log(result) //will print foo2
})
So, you are calling multiple updates without getting their values back; if they fail, you'd never know.
Just one more thing: if something goes wrong along the way, you probably want to rollback all the changes made so far, for that, you should use transactions.
Maybe you should try something like this (not tested):
return Post.sequelize.transaction(function (t) {
Post.findAll({
where: { id: req.query.post_id },
attributes: ['id', 'state']
})
.then((updatedStates) => {
var promises = []
updatedStates.forEach((postState) => {
promises.push(postState.updateAttributes({ state: 2 }, {transaction: t}));
});
return Promise.all(promises);
})
.then((results) => {
return Event.create({
instructions: req.query.instructions,
}, {transaction: t})
})
.then((createdEvent) => {
return Publishing.create({
post_id: req.query.post_id,
event_id: createdEvent.id, //or event_id, depends on your model
start_date: req.query.startDate,
end_date: req.query.endDate,
}, {transaction: t})
});
}).then(function (result) {
// Transaction has been committed
// result is whatever the result of the promise chain returned to the transaction callback
}).catch(function (err) {
// Transaction has been rolled back
// err is whatever rejected the promise chain returned to the transaction callback
});

unread flag is not being updated with Mongoose

I have a conversations collection in my database, and I'm using Mongoose to update the unread flag of a single document.
This is my code:
router.post('/reply/:conversation_id', ensureAuthenticated, (req, res, next) => {
Conversation.findById(req.params.conversation_id, (err, conversation) => {
// If the user that's logged in was the one who created the conversation, and is submitting a reply, run this code
if (req.user._id == conversation.created_by_user_id) {
User.findById(conversation.sent_to_user_id, (err, user) => {
Message.create({
//...
}, (err, message) => {
if (err) {
console.log(err)
} else {
message.conversations.push(conversation._id)
conversation.unread = true
conversation.save() // This is being saved to the database
message.save()
res.redirect('/conversations/' + conversation._id)
}
})
})
} else {
// Otherwise, if the user that's logged in was *not* the one who created the conversation, and is submitting a reply, run this code
User.findById(conversation.created_by_user_id, (err, user) => {
Message.create({
//...
}, (err, message) => {
if (err) {
console.log(err)
} else {
message.conversations.push(conversation._id)
conversation.unread = true
conversation.save() // This is not being saved
message.save()
res.redirect('/conversations/' + conversation._id)
}
})
})
}
})
});
The if part saves conversation.unread = true to the db. The else part does not.
Both parts of the conditional essentially do the same thing (save the conversation's unread flag as true, and save the message), but only the first part of the conditional works when setting unread to true.
Can someone please help me figure out why the unread flag is not being saved as true in the else statement?
You're trying to call save synchronously.
.save takes a callback. It is asynchronous.
See my version below.
router.post('/reply/:conversation_id', ensureAuthenticated, (req, res, next) => {
Conversation.findById(req.params.conversation_id, (err, conversation) => {
// If the user that's logged in was the one who created the conversation, and is submitting a reply, run this code
if (req.user._id == conversation.created_by_user_id) {
User.findById(conversation.sent_to_user_id, (err, user) => {
Message.create({
//...
}, (err, message) => {
if (err) {
console.log(err)
} else {
message.conversations.push(conversation._id)
conversation.unread = true
conversation.save() // This is being saved to the database
message.save()
res.redirect('/conversations/' + conversation._id)
}
})
})
} else {
// Otherwise, if the user that's logged in was *not* the one who created the conversation, and is submitting a reply, run this code
User.findById(conversation.created_by_user_id, (err, user) => {
Message.create({
//...
}, (err, message) => {
if (err) {
console.log(err)
//return here
return res.redirect('/error'); //
} else {
message.conversations.push(conversation._id)
conversation.unread = true
//.save takes a function callback
conversation.save((err) => {
//.save takes a function callback
message.save((err) => {
res.redirect('/conversations/' + conversation._id)
})
})
}
})
})
}
})
});

Using bluebird library in meteor to save data from remote API into local mongo db

Meteor.methods({
'sync.toggl'(apiToken) {
const toggl = new TogglApi({ apiToken });
Promise.promisifyAll(toggl);
toggl.getWorkspacesAsync()
.each(ws => toggl.getWorkspaceProjectsAsync(ws.id)
.map(p => {
Projects.upsert({ projectId: p.id }, {
projectId: p.id,
name: p.name,
tracker: 'toggl',
tags: [],
contributors: []
});
})
.catch(err => console.error(`fetching ${ws.name} projects error - ${err.message}`));
)
.catch(err => console.error(`fetching ${ws.name} workspace error - ${err.message}`));
}});
I'm trying to save data from toggl api into local db here. But Meteor throws an error - Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment. I found couple solutions, but they doesn't allow me to use bluebird promises... or not?
Using async/await worked for me:
Meteor.methods({
'sync.toggl'(apiToken) {
const toggl = new TogglApi({ apiToken });
Promise.promisifyAll(toggl);
async function saveProject(pid, name) {
try {
return await Projects.upsert(
{ pid },
{
pid,
name,
tracker: 'toggl',
contributors: [],
}
)
} catch (err) {
return console.error(`async saveProject failed - ${err.message}`);
}
}
toggl.getWorkspacesAsync()
.each(ws => toggl.getWorkspaceProjectsAsync(ws.id)
.map(p => {
saveProject(p.id, p.name);
})
.catch(err => console.error(`fetching projects error - ${err.message}`))
)
.catch(err => console.error(`fetching workspaces error - ${err.message}`))
}});