I'm trying to update a sequelize model (called conversation) whenever I insert a value into its association (called message). The conversation model doesn't automatically update, and I haven't found any useful information in the docs.
const router = require("express").Router();
const { Conversation, Message } = require("../../db/models");
const onlineUsers = require("../../onlineUsers");
// expects {recipientId, text, conversationId } in body (conversationId will be null if no conversation exists yet)
router.post("/", async (req, res, next) => {
try {
if (!req.user) {
return res.sendStatus(401);
}
const senderId = req.user.id;
const { recipientId, text, conversationId, sender } = req.body;
// if we already know conversation id, we can save time and just add it to message and return
if (conversationId) {
const message = await Message.create({ senderId, text, conversationId });
Conversation.update({ })
return res.json({ message, sender });
}
// if we don't have conversation id, find a conversation to make sure it doesn't already exist
let conversation = await Conversation.findConversation(
senderId,
recipientId
);
if (!conversation) {
// create conversation
conversation = await Conversation.create({
user1Id: senderId,
user2Id: recipientId,
});
if (onlineUsers.includes(sender.id)) {
sender.online = true;
}
}
const message = await Message.create({
senderId,
text,
conversationId: conversation.id,
});
res.json({ message, sender });
}
catch (error) {
next(error);
}
});
module.exports = router;
for update you must change or append data into your record
and second argument is your condition for filter users (if you didnt pass argument for condition it means you didnt want to filter conversations then updade all of the records
await conversation.update(
{ title: 'sample title' },
{ where: { : 2 } }
)
Related
Im creating simple blog posts and trying to connect the post to the logged in user.
When i create a document reference to be stored as a field with reference type, I get a map as shown below:
Here is what I tried
The logged in user is stored in context and the data is sent to an api route along with user as a reference that already exists in the database:
import {useAuth} from '../../context/AuthContext';
page function() {
const {user} = useAuth();
const onSubmit = async () => {
const { title, body } = content;
await axios.post('/api/post', {title, slug: dashify(title), body, author: doc(db, 'users/' + user.uid)
setContent({title: '', content: ''})
}
}
the api code is as follows
const handler = async (req, res) => {
try {
const posts = await getDocs(postsRef);
const postsData = posts.docs.map((post) => post.data());
if (postsData.some((post) => post.slug == "slug")) res.status(406).end();
else {
const newPost = await addDoc(collection(db, 'posts'), {
...req.body,
createdAt: serverTimestamp(),
});
log(newPost, "post details");
res.status(200).json({ newPost });
}
// res.status(201).json({ author });
} catch (e) {
log(e, "error occured post");
res.status(400).end();
}
};
export default handler;
Instead of passing a DocumentReference directly from frontend, try passing the document path and then create a DocumentReference object on server side as shown below:
// API request
await axios.post('/api/post', {
title,
slug: dashify(title),
body,
author: `users/${user.uid}`
})
// Handler
const newPost = await addDoc(collection(db, 'posts'), {
...req.body,
author: doc(db, req.body.author)
createdAt: serverTimestamp(),
});
I have below is a method that signs a user up with their email and password and create a document in Firebase when the user enters their info into a form and clicks submit:
const onSubmitHandler = async (e) => {
e.preventDefault();
try {
const { user } = await createAuthUserWithEmailAndPassword(email, password);
console.log(user, 'user')
await createUserDocumentFromAuth(user, { displayName })
}catch(err) {
if(err === 'auth/email-already-in-use') {
alert('Account with this email already exists');
return;
}else {
console.log(err)
}
}
}
For this function call:
await createUserDocumentFromAuth(user, { displayName })
where displayName can be a string, such as ElonMusk.
In the actual createUserDocumentFromAuth, I am calling the setDoc method, which is one from Firebase to set a user document:
export const createUserDocumentFromAuth = async ( userAuth, additionalInfo = {} ) => {
if(!userAuth) return;
console.log(additionalInfo, 'additionalInfo')
const userDocRef = doc(db, 'users', userAuth.uid);
const userSnapshot = await getDoc(userDocRef);
if(!userSnapshot.exists()) {
const { displayName, email } = userAuth;
const createdAt = new Date();
try {
// set the doc here
await setDoc(userDocRef, {
displayName,
email,
createdAt,
...additionalInfo
});
} catch(err) {
console.log('err creating the user', err)
}
};
return userDocRef;
}
The reason I passed { displayName } in manually is because there is a case where the server's response to createAuthUserWithEmailAndPassword(email, password) has displayName to be null, but we want the user to have a displayName registered in the database.
My question is:
Why does displayName only work when it is passed in as an object and not just in its normal form? For example:
await createUserDocumentFromAuth(user, { displayName })
will replace the displayName: null
But not when I pass in:
await createUserDocumentFromAuth(user, displayName)
What is this technique called in JavaScript?
If you look into createUserDocumentFromAuth, you'll see that it's expects two arguments userAuth and additionalInfo, both arguments are expected to be objects.
It later uses data from additionalInfo to add/overwrite anything in userAuth when calling setDoc() method.
So, I'd recommend add
console.log(userDocRef, {
displayName,
email,
createdAt,
...additionalInfo
});
to see what what data is being sent to setDoc()
I'm fairly new to nodejs and I'm doing a full stack developer challenge from devchallenges.io (Shoppingify). Below, I'm trying to add a new item. However, there's a slight delay between the return value from the request and the actual value in the database. The value updates straight away which is great however, the return value in the request is the previous value rather than being the current quantity value in the database.
// #route POST api/category
// #desc Add category and items
// #access Private
router.post(
'/',
[
check('name', 'Name is required').notEmpty(),
check('category', 'Category is required').notEmpty(),
],
auth,
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
errors: errors.array(),
});
}
const { name, note, image, category } = req.body;
const itemObject = { name, note, image, category };
try {
const categoryItem = await Category.find({
user: req.user.id,
});
// check if category object are empty
if (categoryItem.length === 0) {
const newCat = new Category({
user: req.user.id,
name: category,
items: itemObject,
});
await newCat.save();
res.json(categoryItem);
} else if (categoryItem.length !== 0) {
// check if category name already exists
categoryItem.map(async (cat) => {
if (cat.name.toLowerCase() === category.toLowerCase()) {
cat.items.push(itemObject);
await cat.save();
res.json(categoryItem);
} else {
// create new category
const newCat = new Category({
user: req.user.id,
name: category,
items: itemObject,
});
await newCat.save();
res.json(categoryItem);
}
});
}
} catch (error) {
console.error(error.message);
res.status(500).send('Server Error');
}
}
);
You are not returning the correct item…
Return the result of newcat.save()
Or try a new findById if newCat is not the correct object to return
I'm trying to get a single email from an Office 365 Mailbox.
I'm sending the email id to my app via a POST (req.body.id) and then calling this code in order to get some email properties:
router.post('/id', async function(req, res, next) {
console.log("email with ID -> ", req.body.id)
let parms = { title: 'Inbox', active: { inbox: true } };
const accessToken = await authHelper.getAccessToken(req.cookies, res);
const userName = req.cookies.graph_user_name;
if (accessToken && userName) {
parms.user = userName;
// Initialize Graph client
const client = graph.Client.init({
authProvider: (done) => {
done(null, accessToken);
}
});
try {
const result = await client
.api('/me/messages/', req.body.id)
.select('id,subject,from,toRecipients,ccRecipients,body,sentDateTime,receivedDateTime')
.get();
parms.messages = result.value;
console.log("email -> ", result.value);
res.render('message', parms);
} catch (err) {
parms.message = 'Error retrieving messages';
parms.error = { status: `${err.code}: ${err.message}` };
parms.debug = JSON.stringify(err.body, null, 2);
res.render('error', parms);
}
} else {
// Redirect to home
res.redirect('/');
}
});
At the moment, result.value contains all of the messages in the mailbox instead of just the message with provided id.
Could someone tell me where my error is, please?
The api method has a single path parameter. Calling it like .api('/me/messages/', req.body.id) is effectivly sending it a path ("/me/messages/") along with an additional parameter it ignores.
You need to send it a single string so you'll need to append the req.body.id to the path ({path} + {id}):
const result = await client
.api('/me/messages/' + req.body.id)
.select('id,subject,from,toRecipients,ccRecipients,body,sentDateTime,receivedDateTime')
.get();
inside my users route.
var User = require('../models/user');
router.route('/verify')
.get( (req, res) => {
res.render('verify');
})
.post( (req, res, next) => {
const {secretToken} = req.body;
const user = User.findOne({'secretToken' : secretToken});
if(!user)
{
req.flash('error_msg', 'No user found');
res.redirect('/users/verify');
return;
}
user.active = true;
user.secretToken = '';
user.save();
req.flash('success_msg','Thank you.You can now login');
res.redirect('/users/login');
});
Thats my model
var userSchema = new mongoose.Schema({
username : {
type : String,
index : true
},
password : {
type : String
},
email : {
type : String,
unique : true
},
password : {
type : String
},
secretToken :
{
type : String
},
active : {
type : Boolean
}
});
var User = module.exports = mongoose.model('User', userSchema);
I set a verify route where a user will post his/her secretToken and if the secretToken match with database then that secretToken will uodated to null and my boolean element active will become true from false.So firstly i am taking the secret token from database,then i am checking it with the one which user giving,if match then i am changing my secretToken and active but problem is i cnt save it.It shows me this error.
TypeError: user.save is not a function
My problem is not in creating user,its about updating the info of already created users.
The problem is here:
const user = User.findOne({'secretToken' : secretToken});
findOne returns a Mongoose promise which you are not awaiting. You probably expect to have the document when you call user.save(), but that's not the case. You just need to await the findOne() and then you should be able to call .save() on that document.
What, I'd suggest you to do is:
var User = require('../models/user');
router.route('/verify')
.get((req, res) => {
res.render('verify');
})
.post((req, res, next) => {
const {
secretToken
} = req.body;
User.findOne({
'secretToken': secretToken
}, (user) => {
if (!user) {
req.flash('error_msg', 'No user found');
res.redirect('/users/verify');
return;
}
user.active = true;
user.secretToken = '';
user.save();
req.flash('success_msg', 'Thank you.You can now login');
res.redirect('/users/login');
});
});
I used a callback here, you could also use promises and then try async await functions using babel, but this works for me.