Use result from MongoDB in Javascript file - javascript

I am trying to pass the results from a MongoDB query to use in a Javascript file in my view. I am using handlebars as my view engine. My MongoDB schema is:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var schema = new Schema({
name: {type: String, required: true},
address: {type: String, required: true},
lat: {type: String},
lng: {type: String},
classes: [{
day: String,
start: String,
end: String
}]
});
module.exports = mongoose.model('Dojo', schema);
My routing file has the following:
router.get('/classes', function(req, res, next) {
Dojo.find(function(err, dojos) {
if (err) {
console.error(err);
}
res.render('admin/classes', {
layout: 'layout-admin.hbs',
title: 'Admin',
js: 'classes-admin',
dojos: dojos
});
});
});
Within my hbs file, I have:
<p>{{ dojos }}</p>
The code above shows my variable on the screen OK but when I try to console.log this within script tags I get an Uncaught SyntaxError. My code is:
<script type="text/javascript">
console.log({{ dojos }});
</script>
Any advice on where I'm going wrong would be great appreciated.
Thanks
Matt

Try to change script tag:
<script type="text/javascript">
var mongo_result = {{dojos}};
console.log({{ mongo_result }});
</script>

I ended up switching to EJS as my template engine and used var dojos = <%- JSON.stringify(dojos) %>; which worked great.

Related

Can I update mongoose model that is once already rendered by using fetch?

I'm creating a web s like youtube using express.
and I'm using mongoose for db and pug(jade) template for view.
If I get to the home router("/"), the view file-"Home"- and db array-videos- are rendered.
The home controller looks like this,
import Video from "../models/Video.js";
export const home = async (req, res) => {
let videos = [];
videos = await Video.find({ hashtags: "#rap" }).populate("video");
return res.render("home", { pageTitle: "Home", videos });
};
At this same route, I want to filter my video db and re-render the filtered videos by using fetch. then send those videos to the pug template.
So I created a new function called 'handleVideoFilter()' in my 'main.js'.
const categoryBtn = document.querySelectorAll("#category_bar_chips a");
export const handleVideoFilter = async (event) => {
event.preventDefault();
const clickedCategory = event.target;
const id = clickedCategory.dataset.id;
fetch(`/api/videos/filtered/${id}`, { method: "GET" });
};
Array.from(categoryBtn).forEach((li) =>
li.addEventListener("click", handleVideoFilter)
);
and for this API router and controller are like this.
//router
apiRouter.get("/videos/filtered/:id", getFilteredVideos);
//the controller
export const getFilteredVideos = async (req, res) => {
const { id } = req.params;
const videos = await Video.find({ hashtags: `#${id}` });
return res.render({ videos });
};
But an TypeError occured and I don't see why. The fetch request and getting filltered videos array were successful, I guess there's something wrong with 'return res.render' code.
(node:4172) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received an instance of Object
I'm filltering videos using 'data-id' attribution in the nav, and using mixin to render Video model. the "home" pug file looks like this
include mixins/video
ul#category_bar_chips
a(href="/")
li all
a
li(data-id="music") music
a
li(data-id="rap") rap
a
li(data-id="cooking") cooking
a
li(data-id="pet") pet
a
li(data-id="recent") recent
.contents
.video-wrap
each video in videos
+video(video)
else
h1 No video found :(
here's the video mixin file
here's the Video model schema
//video schema
const videoSchema = new mongoose.Schema({
title: { type: String, required: true, trim: true, maxLength: 50 },
fileUrl: { type: String, required: true },
thumbUrl: { type: String, required: true },
description: { type: String, required: true, trim: true, minLength: 2 },
createdAt: { type: Date, required: true, default: Date.now },
hashtags: [{ type: String }],
meta: {
views: { type: Number, default: 0, required: true },
rating: { type: Number, default: 0, required: true },
},
comments: [
{ type: mongoose.Schema.ObjectId, required: true, ref: "Comment" },
],
owner: { type: mongoose.Schema.Types.ObjectId, required: true, ref: "User" },
});
Sorry If this question was too ambiguous or not professional since I'm new to this whole programming world.
But I'd really like to figure this out. And I don't have a clue what kind of languege or framework to solve this error.
Your answer would be very helpful, thanks a lot for reading.
Is this where the error is getting thrown?
return res.render({ videos });
There is no path specified for the the render method. It should look something like this:
return res.render('videos', { videos });
... where 'videos' is the view you want rendered and {videos} are the values you want to pass back to the view.

Not able to read all the selected checkbox values from pug in express

The Express MDN tutorial here uses the following code to pull in checkbox values from pug.
From the main code, req.body.genre is supposed to return an array of selected values from a form as below
div.form-group
label Genre:
div
for genre in genres
div(style='display: inline; padding-right:10px;')
input.checkbox-input(type='checkbox', name='genre', id=genre._id, value=genre._id, checked=genre.checked )
label(for=genre._id) #{genre.name}
button.btn.btn-primary(type='submit') Submit
when req.body.genre is referenced in the section of code below in the final middleware function where the new Book model instance is created, it returns only the first value stored as string. Hence the genre field always ends up saving only one value even if multiple checkboxes were ticked in the form.
exports.book_create_post = [
// Convert the genre to an array.
(req, res, next) => {
if(!(req.body.genre instanceof Array)){
if(typeof req.body.genre==='undefined')
req.body.genre=[];
else
req.body.genre=new Array(req.body.genre);
}
next();
},
// Validate fields.
body('title', 'Title must not be empty.').isLength({ min: 1 }).trim(),
body('author', 'Author must not be empty.').isLength({ min: 1 }).trim(),
body('summary', 'Summary must not be empty.').isLength({ min: 1 }).trim(),
body('isbn', 'ISBN must not be empty').isLength({ min: 1 }).trim(),
// Sanitize fields.
sanitizeBody('*').escape(),
sanitizeBody('genre.*').escape(),
// Process request after validation and sanitization.
(req, res, next) => {
// Extract the validation errors from a request.
const errors = validationResult(req);
// Create a Book object with escaped and trimmed data.
var book = new Book(
{ title: req.body.title,
author: req.body.author,
summary: req.body.summary,
isbn: req.body.isbn,
genre: req.body.genre
});
The genre field has been defined to store an array of values
var BookSchema = new Schema(
{
title: {type: String, required: true},
author: {type: Schema.Types.ObjectId, ref: 'Author', required: true},
summary: {type: String, required: true},
isbn: {type: String, required: true},
genre: [{type: Schema.Types.ObjectId, ref: 'Genre'}]
}
);
What should i do to be able to get req.body.genre as an array of selected values ?
I found the culprit
This one line of code for express validator created the issue
sanitizeBody('*').escape()
replaced it with
sanitizeBody('author').escape(),
sanitizeBody('title').escape(),
sanitizeBody('isbn').escape(),
sanitizeBody('summary').escape(),
sanitizeBody('genre.*').escape(),
Now everything works fine. the array is now passed through the req body.

Mongoose is not populating (.populate()) on Production (Heroku), but works on Local

Essentially I am having one of those moments. My app's on Heroku, and the DB it uses is mLab (MongoDB).
It works on local (Cloud9), but not on production (Heroku).
I can't get .populate() to work on production.
Do you see any gaps in my code below (snippet) that may cause Heroku to fail, while it works on local?
Thank you.
(I have tried purging the DB (deleting the DB and making a new one. Also I've for similar questions on this site. Also I have tried 'heroku local --tail' command to debug and ran it on my local machine; it works on local... Just not on Heroku; appears buggy.)
People.find(id).populate("friends").exec(function(err, user){
if(err){
console.log("! Error retrieving user. " + err);
reject ("! Error retrieving user. " + err);
}
else {
console.log("0! Friends should be populated: " + user);
resolve(user);
}
});
My model:
var mongoose = require('mongoose');
var personSchema = mongoose.Schema({
name: String,
friends: [
{
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "Person"
},
name: String
}
],
username: String,
password: String,
});
module.exports = mongoose.model("Person", personSchema);
Your API function looks ok.
I suspect your issue is with how your models are setup, or what is in your data-base. I had similar issues the first time I tried to use Heroku, because Localhost is more forgiving.
In order for your API to work, the following 3 things must be setup:
(1) Model file: people.js
must look like something like:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var peopleSchema = new Schema({
name: {
type: String,
required: true,
trim: true
},
friends: [{
type: Schema.Types.ObjectId,
ref: "Friends"
}]
});
const People = mongoose.model('Peoples', peopleSchema);
module.exports = People;
And then you must have a 'Friends' model, that 'People' is referencing.
(2) Model file: friends.js
must look something like:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
// Create the Comment schema
var friendsSchema = new Schema({
friend_name: {
type: String,
required: true,
trim: true
},
});
const Friends = mongoose.model('Friends', friendsSchema);
module.exports = Friends;
And lastly, in order for .Populate to work, you need at least two docs in the database.
(3) Database must contain a Person doc and a Friend doc
must look something like:
people.js :
"_id": {
"$oid": "5bef3480f202a8000984b3c5"
},
"name": "Monica Geller"
"friends": [
{
"$oid": "5bef3480f202a8000984b5b4"
}
]
friends.js :
"_id": {
"$oid": "5bef3480f202a8000984b5b4"
},
"friend_name": "Rachel Green"
Hopefully this helps, or gets you closer to your answer.
It was a version issue.
Had to ensure that all platforms (mLab, and my local database) were using the same version of Mongoose.
npm install mongoose#5.4.8 --save

Nested mongoose Schema giving trouble when trying to query in controller

I'm working on a small project and I have a solution to this problem, but it involves creating a new Schema with a reference to the new Schema in the old Schema. I would like to avoid this if at all possible because it will mean spending a couple hours rewriting some code and messing with tests.
The project is a forum site, and there are three main Schemas that comprise it (in addition to cursory Schemas for the forums, notifications, settings and the schemas for the user and the users activities). The Board Schema (contains a list of all forum sections if that wasn't apparent) Is a Schema that makes a reference to the Threads Schema so it can get the threads for each Board. My problem is in the Thread Schema.
var ThreadSchema = new mongoose.Schema({
... other unrelated Schema stuff...
comments: [{
created: {
type: Date,
default: Date.now
},
creator: {
type: mongoose.Schema.ObjectId,
required: true,
ref: 'User'
},
content: {
type: String,
required: true,
get: escapeProperty
},
likes: [{
type: mongoose.Schema.ObjectId,
required: false,
ref: 'User'
}],
liked: {
type: Boolean,
default: false
},
saved: [{
type: mongoose.Schema.ObjectId,
required: false,
ref: 'User'
}]
}]
});
blah blah blah.
I'm trying to pull for the users profile only the comments that that user has posted. The threads were easy, but comment data is not coming through. The request to the server goes through as successful, but I don't get any data back. This is what I am trying.
obj.profileComments = function (req, res) {
var userId = req.params.userId;
var criteria = {'comments.creator': userId};
Thread.find(criteria)
.populate('comments')
.populate('comments.creator')
.skip(parseInt(req.query.page) * System.config.settings.perPage)
.limit(System.config.settings.perPage + 1)
.exec(function (err, threads) {
if (err) {
return json.bad(err, res);
}
json.good({
records: threads
}, res);
});
};
This is a controller, and the json.bad and json.good are helpers that I have created and exported they basically are res.send.
var good = function (obj, res) {
res.send({
success: 1,
res: obj
});
};
and the bad is very similar, it just handles errors in an obj.res.errors and puts them into messages.
So now that that is all out of the way, I'm a little lost on what to do?
Is this something I should try to handle with a method in my Schema? It seems like I might have a little bit more luck that way. Thank you for any help.

NodeJS "identifier starts immediately after numeric literal" when using a variable JSON object on a jade page

I have a NodeJS App which send a json object from MongoDB on the jade page. In the jade page i can use succefully the json object by using the variabele ${data}, except when i am using it in an javascript in the jade page.Then i get the following error:
SyntaxError: identifier starts immediately after numeric literal
_id: 56c75f2730cc57130ea7e1db },{ tagScore: null,
I read a lot of articles on Stackoverflow. But what i learned from it is that JSON attributes can't handle nummeric values (which is a standaard identifier from mongodb).
But i don't mentioned about a variable json object. Please can you help me to understand and fix this problem.
Example variable JSON Object
{ tagScore: null,
tagCattegory: '',
lookupValue: 'Autoschade',
typeBusinessRule: 'Zoekwaarde',
_id: 56c75f2730cc57130ea7e1db }
Routes.js
req.app.db.models.BusinessRules.pagedFind({
filters: filters,
keys: 'lookupValue tagCattegory tagScore typeBusinessRule',
limit: req.query.limit,
page: req.query.page,
sort: req.query.sort
}, function(err, results) {
if (err) {
return next(err);
}
if (req.xhr) {
res.header("Cache-Control", "no-cache, no-store, must-revalidate");
results.filters = req.query;
console.log("Results XHR ");
res.send(results);
res.json(results);
}
else {
results.filters = req.query;
//res.json(results);
console.log("Results No XHR ");
//console.log(results);
res.render('BusinessRules/index', { data: results.data });
}
});
Jade file
script.
console.log("Load TestData");
var businessRulesData = '{"BusinessRules":[ ' + toString(#{data}) + ']}';
Mongoose schema & model
exports = module.exports = function(app, mongoose) {
var rulesSchema = new mongoose.Schema({
lookupValue: { type: String, required:true},
typeBusinessRule: { type: String},
tagCattegory: { type: String},
tagScore: { type: Number},
creationDate: { type: Date},
search: [String]
});
rulesSchema.plugin(require('./plugins/pagedFind'));
rulesSchema.index({ lookupValue: 1 });
rulesSchema.index({ tagCattegory: 1 });
rulesSchema.index({ typeBusinessRule: 1 });
rulesSchema.index({ tagScore: 1 });
rulesSchema.index({ creationDate: 1 });
rulesSchema.index({ search: 1 });
rulesSchema.set('autoIndex', (app.get('env') === 'development'));
app.db.model('BusinessRules', rulesSchema);
};
Numbers in JSON have to be decimals.
If you want to use hexadecimal then you have to represent it as a string.
Strings have to be quoted.
I solved the problem with the following soluton, is not a clean and nice solution but it works for me
each BusinessRule, i in data
script.
if (Counter < #{data.length}) {
myCurentRecords.push('{"opzoekwaarde": "#{BusinessRule.lookupValue}", "cattegorie": "#{BusinessRule.tagCattegory}", "typeBusinessRule": "#{BusinessRule.typeBusinessRule}", "_id": "#{BusinessRule._id}"},');
}
else {
myCurentRecords.push('{"opzoekwaarde": "#{BusinessRule.lookupValue}", "cattegorie": "#{BusinessRule.tagCattegory}", "typeBusinessRule": "#{BusinessRule.typeBusinessRule}", "_id": "#{BusinessRule._id}"}');
}
Counter++

Categories

Resources