How to print data, retrieved from mongoDB database in Node.js? - javascript

I'm working on a online shop project. I'm using Node.js, express.js and MongoDB with mongoose. I got the product information from the MongoDB database and sending them to the client side. In my case, I can get all these data in my client side but before sending, when I print them to the console in server side, it says undefined.
This is the products schema:
var schema = new Schema({
imagePath: {
type: String,
required: true
},
productName: {
type: String,
required: true
},
productPrice: {
type: Number,
required: true
},
productCategory: {
type: String,
required: true
},
productShortInformation: {
type: String,
required: true
},
productFullInformation: {
type: String,
required: true
},
productViews: {
type: Number,
required: false
},
productStock: {
type: Number,
required: true
}
});
and here is my Node.js code
router.get('/category/summary', function(req, res, next) {
//getting my all products information
var products = Product.find(function (err, docs) {
if(err) {
console.log('Error Happened' + err);
return res.redirect('/');
} else {
//HERE IS THE PROBLEM
//ALL PRODUCT NAME IS SHOWN UNDEFINED
//BUT WHEN I SEND THEM TO THE CLIENT, I GET PRODUCT NAME
for(var product in docs) {
console.log('Name: ' + product.productName);
}
res.render('shop/categorySummary', {
products: docs //sending these information to the client side
});
}
});
});
When I try to print these product name, I get undefined. But in the client side I can print the product information.
I need to manipulate these data before sending them to the client side. So how can I print these product information to the server side(in console) before sending?

for(var product in docs) {
console.log('Name: ' + docs[product].productName);
}
That should work

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.

How to search all keys inside MongoDB collection using only one keyword

Is there a way for MongoDB to search an entire collection's keys' contents using only a single search keyword?
Suppose I have the following collection (let's call it foodCollection):
{
name: "Chocolate Mousse Cake",
type: "Cake"
},
{
name: "Mother's Cookies",
type: "Cookies"
},
{
name: "Dark Bar",
type: "Chocolate"
}
I want my search to look for matches that contain "Chocolate", meaning it should return "Chocolate Mousse Cake" and "Dark Bar".
I'm trying to do this using the ff: code:
Client-side controller
// Search Products
$scope.searchProduct = function () {
$http.get('/api/products/search/' + $scope.searchKeyword).success(function(data){
console.log(data);
})
.error(function(err) {
console.log("Search error: " + err);
});
}
Express.js
app.get('/api/products/search/:param', productController.search); // Search for product
Server-side controller (I used this reference from the MongoDB docs):
// Search
module.exports.search = function(req, res) {
console.log("node search: " + req.body);
Product.find({ $or: [{productName: req.body},
{productType: req.body}]
}, function(err, results) {
res.json(results);
});
}
When I executed this, I got nothing. Am I missing something?
Any help would be greatly appreciated. Thank you.
UPDATE (FINAL)
Finally solved this thanks to Joydip's and digit's tips. Here's my solution in case somebody else gets the same problem as I did:
Client-side controller
$scope.searchProduct = function () {
if ($scope.searchKeyword == '') {
loadFromMongoDB(); // reloads original list if keyword is blank
}
else {
$http.get('/api/products/search/' + $scope.searchKeyword).success(function(data){
if (data.length === 0) {
$scope.showNoRec = true; // my flag that triggers "No record found" message in UI
}
else {
$scope.showNoRec = false;
$scope.productList = data; // passes JSON search results to UI
}
});
}
}
Express.js
app.get('/api/products/search/:keyword', productController.search); // Search for product
Mongoose schema
var mongoose = require('mongoose');
var schema = new mongoose.Schema({
productName: String,
productType: String,
productMaker: String,
productPrice: Number,
createDate: Date,
updateDate: Date
});
schema.index({productName: "text", productType: "text", productMaker: "text"});
Server-side controller
module.exports.search = function(req, res) {
Product.find({$text: {$search : req.params.keyword}}, function(err, results){
res.json(results);
})
}
Thank you everyone for your help. :)
You can try by creating an Index:
db.yourollection.createIndex({"productName":1,"productType":1})
And then by searching for the value, Example:
Product.find({$text:{$search: 'Chocolate'}},{productName:1, productType:1});
If you want to search all key, then you can use
db.foodCollection.createIndex( { name: "text", description: "text" } )
then search by
db.foodCollection.find({ $text: { $search: "choco" } })

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++

Waterline queries similar to HQL

I have models in Sails as follows:
User Model
attributes: {
firstName: {
type: 'string',
required: true
},
lastName: {
type: 'string',
required: true
},
company: {
model: 'Company'
}
}
Company
name: {
type: 'string',
required: true,
unique: true
},
description: {
type: 'string',
required: true
}
In HQL queries, for getting a user working in a specific company, we use something like this:
Select * from User where company.name=?
How can I achieve same in Sails, Right now there are two queries which I am running, one to get User and then another to get company for that user. Is there any way both can be combined in one?
and one more thing, how does waterline deal with scenarios where in we need to get something out of a foreign key directly i.e. If I get user data, then can I get company details by just calling:
User.findOne({id:1}, function(err, res){
//Res contains user data with just companyId now,
//how can i get whole company object here
var companyName = res.company.name; //This is not working currently
})
Try something like this:
User.findOne({id: 1})
.populate('company')
.exec(function(err, user) {
if(err){
//handle errors
}else{
//do stuff
}
});
This should get the values from the association (foreign key).

Categories

Resources