using mongodb with express to get data from database - javascript

I'm just starting out with express, node, and MongoDB and I seem to be experiencing a bit of a problem getting data from mongo in node/express.
I have a database called testdb with a collection called tests and here is the output of tests
{
"_id" : ObjectId("5395f91ced382cec1f8d70f1"),
"name" : "CHATEAU DE SAINT COSME",
"year" : "2009",
"grapes" : "Grenache / Syrah",
"country" : "France",
"region" : "Southern Rhone",
"description" : "The aromas of fruit and spice...",
"picture" : "saint_cosme.jpg"
}
{
"_id" : ObjectId("5395f91ced382cec1f8d70f2"),
"name" : "LAN RIOJA CRIANZA",
"year" : "2006",
"grapes" : "Tempranillo",
"country" : "Spain",
"region" : "Rioja",
"description" : "A resurgence of interest in boutique vineyards...",
"picture" : "lan_rioja.jpg"
}
in routes\index.js I have this
var express = require('express');
var router = express.Router();
var mongo = require('mongodb');
var db = new mongo.Db('testdb', new mongo.Server('localhost',27017),{auto_reconnect:true,safe:false});
var testData = db.collection('tests');
/* GET home page. */
router.get('/', function(req, res) {
testData.find().toArray(function(e,doc){
if(e){
throw e;
}
console.log(doc);
});
res.render('index', { title: 'Express' ,docs:"is jade cool?"});
});
module.exports = router;
as it stands the toArray callback doesn't seem to get called (console.log is not executed and no error is thrown).
if I place res.render in the toArray callback my app hangs in the browser.
since this is my first express app I'm sure I'm making a noob mistake.
I know toArray is async, but it should have been called eventually (and a console log or error should have shown in the terminal)
does anyone know why toArray is not working?

Related

jade iteration through dataset object from mongodb database

i'm building a bookstore app with expressjs and using mongodb to store data i have a database of books i want to display to my index.jade but i keep running into an infinite loop
extends layout
block content
.content
each book in books
.book
img(src="/images/dumbk.png", width="150px", height="200px")
h4.book-title #{book.title}
h6.book-dtls Price: #{book.price} SDG
p.book-desc #{book.description}
a.btn.btn-primary.view(href="/books/details/1") View Book
and this is my index.js
var express = require('express');
var router = express.Router();
var Book = require('../models/bookModel');
/* GET home page. */
router.get('/', /*ensureAuthenticated, */function(req, res, next) {
Book.find({}, function (err, books) {
if (err) {console.log(err);}
var model = {books: books}
console.log(model);
res.render('index', /*{books: books},*/ { title: 'Members' });
});
});
after logging model it logged all the books in my database but it does not render them and keeps running an infinite loop when i tried to log a book title by using book.title in the jade file
-console.log(book.title)
result was undefined
so am sure that the error is in the loop and the formatting
when i log the model the output is
[ { _id: the id, title: "book title", author: "author", price: "10", description: "a book description", stock: "5", cover: "dumbk.png" } ]
You cannot use console.log in the jade file because this is supposed to be a client side script. Your "books" object is back at the server, your console.log will be executed later when the client does it. Try this instead (although there are better ways):
extends layout
block content
each book in books
.book
img(src="/images/dumbk.png", width="150px", height="200px")
h4.book-title #{book.title}
h6.book-dtls Price: #{book.price} SDG
p.book-desc #{book.description}
a.btn.btn-primary.view(href="/books/details/1") View Book
script.
const books = JSON.parse("!{JSON.stringify(books)}");
console.log(books[0] && books[0].title);
Update: according to your comments, you didn't even want this, just to get your Jade file to render books. To do that, you should pass the books array to renderer options:
res.render('index', { title: 'Members', books });

Can't get data from MongoDB database for web app

I'm new to using MongoDB. Currently, I am making a web application that requires some data storage. I established an HTTP server on Node.js that runs on localhost:3000. I also built a virtual development environment using Vagrant and VirtualBox. I am accessing the Mongo shell from PuTTy (if that is relevant at all). Before incorporating MongoDB, it worked fine as I was storing the data in the Node.js program memory.
This web app is an online to-do-list. The first error that I am getting is with the get route. The list of "to-do"s that I have inserted into the Mongo database would not appear on the site in localhost. It seems to not be getting the data from the database. The second error that I am getting is with the post route. When I insert a "to-do" through the user interface at localhost and I refresh the page, the to-do-list on localhost gets updated with that particular to-do (but not with the ones I inserted in the database). But, it doesn't seem to add it into the database, and I still get this error on the console:
vagrant#precise32:~/app$ node server.js
{ description: 'descTest3', tags: [ 'tagTest3' ] }
Mongoose: mpromise (mongoose's default promise library) is deprecated, plug in your own promise library instead: http://mongoosejs.com/docs/promises.html
I'm not sure why I got that error since I do not seem to be using any promises.
server.js
var express = require("express"), http = require("http"), app = express(), mongoose = require("mongoose");
app.use(express.static(__dirname + "/client"));
app.use(express.urlencoded());
mongoose.connect('mongodb://localhost/WatNext');//connect to the WatNext data store in mongoDB
var ToDoSchema = mongoose.Schema({
"description": String,
"tags": [ String ] //array of Strings
});
var ToDo = mongoose.model("ToDo", ToDoSchema)
http.createServer(app).listen(3000);
//get and post routes:
app.get("/toDos.json", function (req, res) {
ToDo.find({}, function (err, toDos) {
if (err != null){
console.log(err);
}
res.json(toDos);
});
});
app.post("/todos", function (req, res) {
console.log(req.body);
var addedToDo = new ToDo({"description" : req.body.description, "tags" : req.body.tags});
//save function saves object into the database
addedToDo.save(function (err, result) {
if (err != null){//if there is an error
console.log(err);
res.send("ERROR SAVING");
}
else {
ToDo.find({}, function (err, result) {
if (err != null){//if there is an error in finding
res.send("ERROR FINDING");
}
res.json(result);
});
}
});
});
app.js
var main = function (toDoObjects) {
//do stuff with ToDoObjects including outputting the list of ToDos
};
$(document).ready(function() {
$.getJSON("toDos.json", function(toDoObjects) {
main(toDoObjects);
})
});
mongo shell
> show dbs
WatNext 0.0625GB
local 0.03125GB
> use WatNext
switched to db WatNext
> show collections;
system.indexes
toDoCollection
todos
> db.toDoCollection.find();
{ "_id" : ObjectId("58b38dd8fb355f57162d9cf1"), "description" : "Get groceries and eat afterwards", "tags" : [ "shopping", "chores" ] }
{ "_id" : ObjectId("58b38dd8fb355f57162d9cf2"), "description" : "Make up some new To-Dos", "tags" : [ "writing", "work" ] }
{ "_id" : ObjectId("58b38dd8fb355f57162d9cf3"), "description" : "Prep for Monday's class", "tags" : [ "work", "teaching" ] }
{ "_id" : ObjectId("58b38dd8fb355f57162d9cf4"), "description" : "Answer emails", "tags" : [ "work" ] }
{ "_id" : ObjectId("58b38dd8fb355f57162d9cf5"), "description" : "Take April to the park", "tags" : [ "chores", "pets" ] }
{ "_id" : ObjectId("58b38dd8fb355f57162d9cf6"), "description" : "Finish writing this book", "tags" : [ "writing", "work" ] }
EDIT:
I found out it was just an error of naming.
I also found out that
mongoose.Promise = require("bluebird");
solved the problem with the promise error. Remember to install the module first though:
npm install --save bluebird
I found out what was wrong. It was an error in naming for the GET and POST routes. It should have been:
app.get("/todos.json", function (req, res) { //get the data from the collection called 'todos' in MongoDB
as well as:
$.getJSON("todos.json", function(toDoObjects) {
I should have used the todos collection instead of toDoCollection:
"description" : "descTest1", "_id" : ObjectId("58b39a1fb1a30305075408fa"), "tags" : [ "tagTest2" ], "__v" : 0 }
{ "description" : "descTest2", "_id" : ObjectId("58b4c837d47a5604c7c0609a"), "tags" : [ "tagsTest2" ], "__v" : 0 }
{ "description" : "descTest3", "_id" : ObjectId("58b4ca0491f4c804d200cda9"), "tags" : [ "tagTest3" ], "__v" : 0 }
{ "description" : "descTest4", "_id" : ObjectId("58b4e636b71d0a05ebb7a71a"), "tags" : [ "tagTest4" ], "__v" : 0 }
{ "description" : "descTest5", "_id" : ObjectId("58b60211428520053a4714ed"), "tags" : [ "tagTest5" ], "__v" : 0 }
{ "_id" : ObjectId("58b6037839e65d96e13cf68e"), "description" : "descTestMONGO", "tags" : [ "tagTestMONGO" ] }
{ "_id" : ObjectId("58b605b339e65d96e13cf690"), "description" : "Take April to the park", "tags" : [ "chores", "pets" ] }

make a POST api call in express router with request

I am trying to make a POST request that returns data to me. I then want to push this data to my route to be added to my index route. heres my API call:
https://api.locu.com/v2/venue/search
{
"api_key" : "my API key",
"fields" : [ "name", "description", "location", "contact", "website_url", "menu_url", "open_hours" ],
"venue_queries" : [
{
"categories" : "restaurant",
"location" : {
"geo" : {
"$in_lat_lng_radius" : [44.0521, -123.116207, 6000]
}
},
"delivery" : {
"will_deliver" : true
}
}
]
}
If I make this request in postman then I get the data I would expect.
I would like to use request to make this api call. I have tried like this:
var express = require('express');
var router = express.Router();
var request = require('request');
var params = {
"api_key" : "myApiKey",
"fields" : [ "name", "description", "location", "contact", "website_url", "menu_url", "open_hours" ],
"venue_queries" : [
{
"categories" : "restaurant",
"location" : {
"geo" : {
"$in_lat_lng_radius" : [44.0521, -123.116207, 6000]
}
},
"delivery" : {
"will_deliver" : true
}
}
]
}
request.post({url:'https://api.locu.com/v2/venue/search', params}, function(err,httpResponse,body){
var resBody = JSON.parse(body)
console.log(resBody);
})
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
Just to console.log the results but I get the error:
{ status: 'error',
http_status: 400,
error: 'Request body is not a valid JSON object.' }
Is this because of the way I'm passing in my params? How can I send this data to my '/' route? can I just save it to a variable then pass it in? Or is there a better pattern for this?
You need to specify your params as the bodyof the request, and you should also probably set the content type to JSON:
request.post({
url:'https://api.locu.com/v2/venue/search',
body:params,
json: true
}, function(err, response, body){
console.log(body);
})

adding an object that represents users to an array after signup using passport

I am trying to make a list of username and passwords so that when a user signs in with their credentials they can see all the data that everyone else sees but they still have to use their own credential. I wanted to make a list of objects like this users : [{username : "user1", password : "pass1"}, {username : "user2", password : "pass2"}]. this should be created on signup. I though subdocs would help but I'm not getting what I want. I have this:
var userlist = new mongoose.Schema({username: String, password : String })
var userSchema = new mongoose.Schema({
users : [userlist]
})
and I attempted to add the new users to the array like this:
app.post("/signup", function(req, res){
var user = new User;
user.users.push({username : req.body.username, password : req.body.password})
user.save(function(err){
if(err) return handleError(err);
console.log("success")
})
// User.create(users : [{username : req.body.username, password : req.body.password}], function(err, doc){
// console.log(doc);
// })
res.redirect("/login")
})
this givs me this
> db.users.find().pretty()
{
"_id" : ObjectId("56ba6219763de71c03199a70"),
"users" : [
{
"username" : "user1",
"password" : "pass1",
"_id" : ObjectId("56ba6219763de71c03199a71")
}
],
"__v" : 0
}
{
"_id" : ObjectId("56ba6225763de71c03199a72"),
"users" : [
{
"username" : "user2",
"password" : "pass2",
"_id" : ObjectId("56ba6225763de71c03199a73")
}
],
"__v" : 0
}
>
It's making separate documents. I want it to look like this
{
"_id" : ObjectId("56ba6219763de71c03199a70"),
"users" : [
{
"username" : "user1",
"password" : "pass1",
"_id" : ObjectId("56ba6219763de71c03199a71")
},
{
"username" : "user2",
"password" : "pass2",
"_id" : ObjectId("56ba6225763de71c03199a73")
}
],
"__v" : 0
}
Having the objectIDs in the subdocs are not so important to me . I just want to group all the users together so that when they go to login I could do something like if the doc is there the credentials are good so continue to other parts of website.
I am not sure if you have resolved you question by now or not, regardless here is the answer to your problem.
Firstly if you don't need _id in subdocument then state that in the schema accordingly and no _id will be created.
var userSchema = new Schema({ username: String, password: String},{ _id: false });
If you use the above schema for user then there should be no _id field in the subdocument.
You should know that to insert a subdocument you need to know the parent for it. If you don't provide the parent while inserting the subdocument then for each insert a new parent is created. In this case parent contains _id and users subdocument. If I have the exact problem, I would go about solving it the following way:
The schema designs remain the same as shown below (I named them differently to avoid confusion):
var userSchema = new Schema({username: String, password: String},{ _id : false });
var userListSchema = new Schema({
users: [userSchema]
});
Now I will declare the parent model as follow:
var UserList = mongoose.model('UserList', userListSchema);
//see below what list gets assigned.
var list;
Now let's assume I have a route handler where I would like to keep adding the users upon sign up something as shown below:
app.get("/newuser/:username/:password", function(req, res) {
//create user model
var User = mongoose.model('User', userSchema);
//load user module, for testing i use params, you can change this to req.body
var user = new User({username: req.params.username, password: req.params.password});
//I would like to find the first document in userlists collection
UserList.findOne({}, function(err, result) {
if(err) console.log(err);
//below if condition is true, if there is one document with users subdoc
if(result) {
console.log('Found existing document with users subdocument. Adding user to array.')
//assign the parent where the subdoc should be inserted to list
list = result;
//there already is a document with subdocument users, so append to it
list.users.push(user);
//save the changed list.
list.save(function(err) {
if (err) console.log(err);
console.log('User saved.');
});
} else {
console.log('No document found. Creating one and adding this user to users subdocument.');
// initialize list model with first ever user
list = new UserList({ users: [user] });
//save the new changed list
list.save(function(err) {
if (err) console.log(err);
console.log('User saved.');
});
}
})
});
Done. Now when I run the app and access the following URL for the first time
http://127.0.0.1:8080/newuser/user1/pass1
The userslist collection would look as follow:
> db.userlists.find().pretty();
{
"_id" : ObjectId("56c349d6479f5b9b1eaea1c8"),
"users" : [
{
"password" : "pass1",
"username" : "user1"
}
],
"__v" : 0
}
I would like to access the link with different params as shown below:
http://127.0.0.1:8080/newuser/user2/pass2
And the output of the collection looks as follow:
{
"_id" : ObjectId("56c349d6479f5b9b1eaea1c8"),
"users" : [
{
"password" : "pass1",
"username" : "user1"
},
{
"password" : "pass2",
"username" : "user2"
}
],
"__v" : 1
}
Now I terminate the app and then re-run the app and access the following url:
http://127.0.0.1:8080/newuser/user7/pass7
And the output of the collection looks as follow:
{
"_id" : ObjectId("56c349d6479f5b9b1eaea1c8"),
"users" : [
{
"password" : "pass1",
"username" : "user1"
},
{
"password" : "pass2",
"username" : "user2"
},
{
"password" : "pass7",
"username" : "user7"
}
],
"__v" : 2
}
There you go. I feel bad to see that userlists collection would always always always have one document and its array would keep expanding, maybe not a good practice to solve your issue in this manner. If I were you, I would store each user as a single record and then do the group by or any other aggregation operation.

Mongoose not returning, but mongo shell is

I'm using mongoose on my node app, and I want to get a seller by its email:
getSellerByEmail : function(email,next){
var Seller = mongoose.model('Seller');
console.log(inspect(email));
Seller.findOne({'email' : new RegExp(email, 'i')}, function(seller){
next(seller);
});
}
When I try to login, mongoose does not return the new user. But when I try to create another user with the same email, the server executes this function correctly and it returns the new user.
Also tried with {'email' : email} and It returns null, but when I do this query on mongo shell, it returns correctly.
db.sellers.findOne({email : 'email#email.email'});
{
"_id" : ObjectId("54b94759b042bdbf19cb7b97"),
"name" : "Nome da Empresa",
"cnpj" : "123123123",
"email" : "email#email.email",
"password" : "$2a$08$6UvW8Bux3CwUMok8ac12Sehbd.xCHnVUI51ZwhtGKBjkSa6/MrqUu",
"__v" : 0
}
I'm new to mongodb + mongoose, so I know it's a dumb question, but I just can't realize what is wrong... I've also created a findSellerById() function, and it works perfectly.
EDIT 1:
Using Mongoose debug, here's what it's printed:
Mongoose: sellers.findOne({ email: 'email#email.email' }) { fields: undefined }
Mongoose: sellers.findOne({}) { fields: undefined }
As you can see, also tried with no parameters, no success...
I had the same problem, maybe you could try this:
Seller.find({email: seller.email}, function(err, seller){
console.log(seller);
});
This solved mine, hope it will solve yours too !
The callback function passed into findOne takes two parameters (error and doc), so you're treating seller as the error parameter instead of the doc parameter.
So your function should look like this instead:
getSellerByEmail : function(email,next){
var Seller = mongoose.model('Seller');
console.log(inspect(email));
Seller.findOne({'email' : new RegExp(email, 'i')}, function(err, seller){
next(seller);
});
}

Categories

Resources