How can I do multiple ajax without submitting a form.
I am trying to update the data in the database when someone clicks the checkbox and then updating that particular div where the data has been updated in the database. I want to achieve this without reloading the whole page.
I manage to do the first part, but I am stuck in the second part because I don't know how to do multiple ajax requests.
I am using Pug for the front-end, NodeJS for the back-end, and MongoDB for database.
Schema
const userSchema = new mongoose.Schema({
name: {
type: String,
trim: true,
},
todos: [
{
task: {
type: String,
trim: true,
required: 'Please Enter your Task',
},
dueDate: {
type: Date,
default: new Date(+new Date() + 3 * 24 * 60 * 60 * 1000),
},
dueTime: String,
done: {
type: Boolean,
default: false,
},
},
],
});
routes
router.get('/', catchErrors(todoControllers.todo));
router.post('/',catchErrors(todoControllers.addTodo));
router.put('/todo/:id', catchErrors(todoControllers.checkStatus));
Controller
const mongoose = require('mongoose');
const User = mongoose.model('User');
exports.todo = async (req, res) => {
const user = await User.findById(req.user._id);
if (user.todos.length) {
const updatedUser = await User.aggregate([
{ $unwind: '$todos' },
{ $sort: { 'todos.dueDate': 1 } },
{ $group: { _id: '$_id', todos: { $push: '$todos' } } },
]);
res.render('todos', { updatedUser: updatedUser[0].todos });
} else {
res.render('layout');
}
};
exports.addTodo = async (req, res) => {
const add = {
todos: {
task: req.body.task,
dueDate: req.body.dueDate,
dueTime: req.body.dueTime,
},
};
const user = await User.findOneAndUpdate(
{ _id: req.user._id },
{ $push: add },
{ new: true }
).exec();
req.flash('success', 'saved');
res.redirect('/');
};
exports.checkStatus = async (req, res) => {
const updatedUser = await User.findOneAndUpdate(
{ todos: { $elemMatch: { _id: req.params.id } } },
{ $set: { 'todos.$.done': req.body.done } }
);
};
main.js (it is the main client-side javascript file)
$('.todo--checkbox').change(function () {
let value = $(this).data('value');
$.ajax({
url: `/todo/${value}`,
type: 'PUT',
data: { done: this.checked },
});
});
Pug file
.todos
if updatedUser
h5 Task
each todo in updatedUser
- let dueDate = h.moment(todo.dueDate).format("dddd DD MMMM YYYY")
if !todo.done
.card
.card-content
label
input(type="checkbox" data-value=todo._id ).todo--checkbox
span= `${todo.task} - ${todo._id}`
if (dueDate === h.moment(Date.now()).format("dddd DD MMMM YYYY"))
p.due--date--time
span.material-icons.red-text notifications
| Today at #{todo.dueTime}
else
p.due--date--time
span.material-icons notifications
| #{dueDate}
h5 Completed
each todo in updatedUser
if todo.done
.card
.card-content
label
input(type="checkbox" checked data-value=todo._id ).todo--checkbox
span= `${todo.task}`
else
br
h3 No Task
I want to update the .todos div when anyone checks the checkbox.
How can I use ajax to update .todos?
Related
I have created a cron job to update some data in the database, but the query is never executed.
my cron job :
const cron = require('node-cron');
const Document = require('../models/document');
const User = require('../models/user');
const checkDocumentsDate = cron.schedule(
'*/1 * * * *',
async () => {
console.log('here');
Document.find().populate('user', (err, docs) => {
console.log(err);
if (!err) {
docs.forEach((doc) => {
console.log(doc);
});
}
});
},
{
scheduled: false,
}
);
exports.startCheckDocumentsDate = () => {
checkDocumentsDate.start();
};
I call the startCheckDocumentsDate in app.js like :
// CronJobs
const { startCheckDocumentsDate } = require('./services/cron_tasks');
// DB Connection
mongoose
.connect(process.env.DATABASE, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
})
.then(() => {
console.log('DB CONNECTED');
startCheckDocumentsDate();
});
my console.log() :
DB CONNECTED
here ===> console.log() inside cron job
here
here
here
here
here
here
here
Here is my document model , the user model is also look a like:
const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2');
const { ObjectId } = mongoose.Schema;
const documentSchema = new mongoose.Schema(
{
doctype: { type: String, required: true },
url: {
type: String,
},
filename: { type: String, required: true },
fileid: { type: String, required: true, unique: true },
verificationcount: {
type: Number,
default: 0,
},
verificationfailedcount: {
type: Number,
default: 0,
},
expiredate: Date,
user: {
type: ObjectId,
ref: 'User',
required: true,
},
idstabile: {
type: ObjectId,
ref: 'Stabile',
},
opinionby: [
{
type: ObjectId,
ref: 'User',
},
],
opinionbyadditionalinfo: [
{
user: {
type: ObjectId,
ref: 'User',
},
approved: {
type: Boolean,
},
},
],
},
{ timestamps: true },
);
documentSchema.index({ user: 1, filename: 1 }, { unique: true });
documentSchema.plugin(mongoosePaginate);
module.exports = mongoose.model('Document', documentSchema);
Couldn't find why it isn't working. Probably there is something wrong with it.
Also moongose version is "mongoose": "^5.7.7"
Try to use .then instead of defining callback in .populate:
Document.find().populate('user').then((err, docs) => {
Since you are using async function, you can also refactor your code to use await syntax:
const checkDocumentsDate = cron.schedule('*/1 * * * *', async () => {
try {
console.log('here');
let docs = await Document.find().populate('user');
docs.forEach((doc) => { console.log(doc); });
} catch(error) {
console.log(err);
}
},{
scheduled: false,
});
I came to a problem, where I can create conversations with multiple people 2 and so on. However, I can't understand why it doesn't store data to seperate User models.
Here is a code that you only need to know:
router.post(
"/",
auth,
[
check("conversators", "There should be at least two conversators").isLength(
{ min: 2 }
),
],
async (req, res) => {
const { conversators } = req.body;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
try {
let conversation = new Conversation({
user: req.user.id,
conversators: conversators,
});
await conversators.map(async (conversator) => {
let user = await User.findById(conversator);
let newData = user;
newData.conversations.push(conversation.id);
console.log('Created data', newData);
let newUser = await User.findOneAndUpdate(
{ user: conversator },
{
$set: {
newData,
},
},
{ new: true }
);
await newUser.save();
console.log(newUser);
});
await conversation.save();
res.status(200).json(conversation);
} catch (error) {
console.error(error.message);
res.status(500).send("Server error.");
}
}
);
module.exports = router;
What I can assure is that this line: console.log('Created data', newData); prints the desired data. However, the next console: console.log(newUser); prints the same User model as the previous one.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
name: {
type: String,
required: true,
},
surname: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
conversations: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "conversation",
},
],
date: {
type: Date,
default: Date.now,
},
});
module.exports = User = mongoose.model("user", UserSchema);
The reason might be the difference in search methods used to get a record for newData and newUser. You have used User.findById for newData, which will obviously return different objects for different ids. But User.findOneAndUpdate uses filter criteria that may satisfy several results, but only first will be returned. So it boldly depends on what that user field is.
Here is the part that I changed and started to see the data on MongoDB:
await conversators.map(async (conversator) => {
let user = await User.findById(conversator);
let newData = user;
newData.conversations.push(conversation.id);
new Promise(async (resolve, reject) => {
user = await User.findOneAndUpdate(
{ id: conversator },
{
$set: {
newData,
},
},
{ new: true }
);
return resolve;
})
return await user.save();
});
Posted on behalf of the question asker
At this moment I try to find the query which works in this case, but then want to update the object. So I want to check if review object exist and if not then create that key name first and then push that object into an array. Else push into that in existing object of array.
Default object looks like (without review object):
const mongoose = require('mongoose');
const musicSchema = mongoose.Schema({
id: {
type: Number,
required: true
},
artist: {
type: String,
required: true
},
title: {
type: String,
required: true
},
release_year: {
type: Number,
required: true
},
genre_id: {
type: Number,
required: true
},
image_url: {
type: String,
required: true
},
reviews: [{
id: {
type: Number,
required: true
},
locale: {
type: String,
required: true
},
rating: {
type: Number,
required: true
},
comment: {
type: String,
required: true
}
}]
});
const Music = mongoose.model("Music", musicSchema); // now we have to create our model
console.log;
module.exports = Music; // export our created model
app.post('/addReview/:id', async (req, res) => {
let idNumber = parseInt(req.params.id); // 501437
let reviewObject = req.body; // {id: "501437", locale: "nl", rating: 3, text: "helello"}
try {
const music = client.db('database').collection('music');
const query = { id: idNumber };
const musicSong = await music.findOne(query);
await musicSong.update({ $push: { reviews: reviewObject } }); // error comes from here
} catch (err) {
console.log(err);
}
});
check if reviews field is not exists then initialise it to blank array
push object to reviews
save() to save main document
app.post('/addReview/:id', async (req, res) => {
let idNumber = parseInt(req.params.id); // 501437
let reviewObject = req.body; // {id: "501437", locale: "nl", rating: 3, text: "helello"}
try {
const music = client.db('database').collection('music');
const query = { id: idNumber };
let musicSong = await music.findOne(query);
if (!Array.isArray(musicSong.reviews)) {
musicSong.reviews = [];
}
musicSong.reviews.push(reviewObject);
music.save();
} catch (err) {
console.log(err);
}
});
Second option using updateOne():
It does not require to find, check and save operations if you use update methods,
app.post('/addReview/:id', async (req, res) => {
const query = { id: parseInt(req.params.id) };
let reviewObject = req.body;
try {
const music = client.db('database').collection('music');
await music.updateOne(query, { $push: { reviews: reviewObject } });
} catch (err) {
console.log(err);
}
});
How can I update data in MongoDB when I check the checkbox without submitting any form.
My Schema
const userSchema = new mongoose.Schema({
name: {
type: String,
trim: true,
},
todos: [
{
task: {
type: String,
trim: true,
required: 'Please Enter your Task',
},
dueDate: {
type: Date,
default: new Date(+new Date() + 3 * 24 * 60 * 60 * 1000),
},
dueTime: String,
done: {
type: Boolean,
default: false,
},
},
],
});
I want to update the done element which is in todos array.
I tried to do this.
Main Client Side JavaScript
$(document).ready(function () {
$('.todo--checkbox').change(function () {
let isChecked;
if (this.checked) {
isChecked = true;
$.ajax({
url: '/todo/' + this.value,
type: 'PUT',
data: { done: true },
});
} else {
isChecked = false;
$.ajax({
url: '/todo/' + this.value,
type: 'PUT',
data: { done: false },
});
}
});
});
In the front-end I have set the value of the checkbox to the _id of the object.
/routes/index.js here I am handling my routes
router.put('/todo/:id', todoControllers.checkStatus);
And Finally I am handling that contorller in my todoCOntroller.js
exports.checkStatus = async (req, res) => {
try {
const user = await User.aggregate([
{ $unwind: '$todos' },
{ $match: { 'todos._id': req.params.id } },
]);
// res.json(user);
console.log(user);
} catch (err) {
console.log('error: ', err);
}
};
But I am not getting any user in my console.
Please tell me where I am wrong.
You don't need to use aggregate. You can do it by using $elemMatch
const user = await User.find({
todos: { $elemMatch: { _id: req.params.id } },
});
For more information read the docs
Hi everyone I am making a route to get the items that are created by the logged-in user but when I use the .filter function I get an error. Not sure why I am getting this error. I have made other apps before doing the same thing and never got an error
Item.filter is not a function
The my-items route
const requireAuth = require("../middleware/requireAuth");
const express = require("express");
const mongoose = require("mongoose");
const Item = mongoose.model("Item");
router.get("/my-items", requireAuth, async (req, res) => {
try {
const items = Item.filter((item) => item.userId === req.user.userId);
res.send(items);
} catch (err) {
console.log(err);
}
});
Item Schema
const mongoose = require("mongoose");
const itemSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
phone: {
type: mongoose.Schema.Types.String,
ref: "User",
},
email: {
type: mongoose.Schema.Types.String,
ref: "User",
},
seller: {
type: mongoose.Schema.Types.String,
ref: "User",
},
title: {
type: String,
required: true,
},
category: {
type: String,
required: true,
},
detail: {
type: String,
requiredL: true,
},
condition: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
});
mongoose.model("Item", itemSchema);
const items = await Item.find(({userId:req.user.userId}).lean();
it should return exact items from db that you want you can use more query if you need.
Item is a model but not the documents in the database, you need to do a query first in order to get the items.
router.get("/my-items", requireAuth, async (req, res) => {
try {
const query = Item.find()
query.exec().then(items => {
const filteredItems = items.filter((item) => item.userId === req.user.userId);
res.send(items);
})
} catch (err) {
console.log(err);
}
});
This error can occur when you are trying to use the array methods on other data structures.
This piece of code returns an error .filter is not a function:
const myList = await getList().filter(item => item.myKey > 10);
Solution:
const data = await getList();
const myList = data.filter(item => item.myKey > 10);