Nodejs, Mongoose and Jade get no data from Database - node.js

i was searching for my Problem but even don't know where is the problem.
I get the title which is set in my route but no data from the database...
My model:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = Schema.Types.ObjectId;
var blogSchema = new Schema({
title: { type: String, required: true },
author: { type: String, required: true },
body: { type: String, required: true },
date: { type: String, required: true },
hidden: Boolean
});
module.exports = mongoose.model('Blog', blogSchema);
my router:
var express = require('express'),
Blog = require('../models/blog'),
moment = require('moment');
moment.lang('de');
var router = express.Router();
router.get('/articles', function(req, res) {
Blog.find(function(err, docs){
return res.render('blog/articles', {
title: 'Blog_',
articles: docs
});
});
});
app.use('/blog', router);
my jade
extends ../layouts/default
include ../elements/form-elements
block content
h1= title
each article in articles
.col-md-12
div.title= article.title
the only one i get displayed at the Page is
Blog_
So what iam doing wrong?
At the error file it only says:"Cannot read property 'title' of undefined"
So the articles objects are not set...but why?
Thanks so much
edit 1:
change article.title to article doesn't change anything
in the log files is
GET /blog/articles HTTP/1.1 304 - - 3 ms
edit 2:
it seems that node doesnt get any data from the db...
and yes there is one testdata set ;)
console.log() ->
err: null
docs: []
Solution is posted as answer

got the solution...
the model wasn't right...
var blogSchema = new Schema({
title: { type: String, required: true },
author: { type: String, required: true },
body: { type: String, required: true },
date: { type: String, required: true },
hidden: Boolean
}, {collection : 'blog'});
have to name the collection at the end...cause its written in small letters -.-
What a false - never ever do it again ^^

I know this is a very old question and it's marked by OP as answered, but I think the real problem was in "my router", you're not referencing your "docs" (the data coming back from the database) correctly. Keep in mind "docs" is an array so you would need to reference them like this:
router.get('/articles', function(req, res) {
Blog.find(function(err, docs){
return res.render('blog/articles', {
title: docs[0].title, // Get the title for first entry
articles: docs[0].body // Get body for the first entry
});
});
});
I'm hardcoding the array index but you can use a loop to get every item from the array.
I don't think OPs solution fixes the problem because...
By default, when compiling models with:
const someModel = mongoose.model('someModel', SomeSchema);
mongoose creates a collection using 'someModel' name and adding an "s" at the end, so if you check your database, your collection should
appear as 'someModels'. With OP's solution:
{ collection: 'blog' }
as the second parameter when creating the blog schema
var blogSchema = new Schema();
That default behavior is overwritten and the name of your collection will be whatever you set as the value for collection, in this case, "blog".
You can read more about it in Mongoose official docs
or in the Models section in MDN - Node/Express/Mongoose

Related

how can i get data from an db object which is store id of another db in mongoDB

hi there I am not getting data from a DB object which is storing the id of another DBS, actually, this is a blog website so I am posting comments and acting comments but there are problems I am getting the same comments on all posts but I want, every post should have their own comment.
here is post schema
const blogSchema = new mongoose.Schema({
title: String ,
content: String,
image:{data: Buffer,contentType: String},
comment:[
{
type:mongoose.Schema.Types.ObjectId, ref:'Comment'
}
]
});
here is the comment schema
var commentSchema = new mongoose.Schema({
name:{
type:String,
required: "this field is required"
},
comment:{
type:String,
required:"this filed is required"
},
blog:{
type:mongoose.Schema.Types.ObjectId,
ref: 'Blog'
}
},{
timestamps: true
})
node js router which is getting post but not comment
pp.get("/post/:postname",(req,res)=>{
// const requesttitle = _.lowerCase(req.params.postname);
const requesttitle = req.params.postname;
Blog.findOne({_id: requesttitle} ,(err ,got)=>{
if(err){
console.log(err)
}else{
const data= got.comment.find({})
console.log(data)
res.render('post',{post:got });
}
})
})
I believe the problem lays in your Schema. In your blogSchema you have references to many Comment documents, and in your commentSchema you have a reference to a single "Blog" ( I suggest not naming it "blog" but "post" since that is what it is ) . This duplicative referencation is not necessary in most cases.
Since in your setup a single comment can only be a child of one specific post, this would be the reference I would go for. The post document itself doesn't really need to know directly what comments are included since that information is already hold in the Comment document.
For your post I would suggest the following schema :
// Post Schema
const postSchema = new mongoose.Schema({
title: String ,
content: String,
image: { data: Buffer, contentType: String }
});
For your comment I would suggest the following schema :
// Comment Schema
const commentSchema = new mongoose.Schema({
name: {
type: String,
required: "this field is required"
},
comment: {
type: String,
required: "this filed is required"
},
post: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
}
});
Now sure the next step depends on your whole frontend part is setup up, but having schemas like this would let you do something along the lines of :
pp.get("/post/:id", async (req,res) => {
const id = req.params.id;
const post = await Post.findOne({ _id: id });
const comments = await Comment.find({ post: id });
res.render('post', {
post: post,
comments: comments
});
});
Pros
one-directional relation means less work if a comment is created or deleted.
possibility to just get comment and/or post or both in one api call.
Cons
Requires 2 database calls if post and comments both are requested.
Alternative: Subdocuments
As an alternative to using referenced Documents you can use Subdocuments.
For your commentSchema that means you won't need to create a seperate Model out of it. However your postSchema would need to look like this:
const commentSchema = new mongoose.Schema({
message : { type : String }
});
const postSchema = new mongoose.Schema({
comments : [commentSchema]
});
👆 This would by default include all comments of the post if you retrieve the post from the database. However it would also require a different code for interacting with those comments (adding, deleting, ...) but you can read about it in the docs I am sure.

Node Mongoose - saving embedded documents on API once receiving mongoId

I would like to know the best approach to solve the current scenario.
I've got a node API which uses mongoose and bluebird. And some Android clients will post "movement" entities to it.
(Question at the end).
Let's say movement-model.js exports the Schema, and looks like this:
"use strict";
const mongoose = require('mongoose');
const _movementSchema = {
movementId: { type: Number, requried: true },
relMovementId: Number,
_party: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'Party' }
}
module.exports = mongoose.Schema(_movementSchema, {collection: 'movement'});
And related exported Schema on party-model.js is as follows:
"use strict";
const mongoose = require('mongoose');
const _partySchema = {
active: { type: Boolean, default: true },
name: { type: String, trim: true, required: true },
logo: { type: Buffer },
coordenates: { lat: Number, long: Number },
startOn: { type: Date, required: true },
endOn: { type: Date, required: true }
}
module.exports = mongoose.Schema(_partySchema, {collection: 'party'});
Android client would send the JSON with ObjectId and not full populated object. So when the POST comes, I'm using it directly (i.e: let _movement = req.body;) and on the movement-dao.js I've got the createNew method and I'm exporting the Model:
"use strict";
const mongoose = require('mongoose');
const Promise = require('bluebird');
mongoose.Promise = Promise;
const movementSchema = require('../model/movement-model');
movementSchema.statics.createNew = (movement) => {
return new Promise((resolve, reject) => {
if (!_.isObject(movement)) {
return reject(new TypeError('Movement is not a valid object.'));
}
let _something = new Movement(movement);
_something.save((err, saved) => {
err ? reject(err)
: resolve(saved);
});
});
}
const Movement = mongoose.model('Movement', movementSchema);
module.exports = Movement;
What I want to accomplish is to: save the movement collection with the _party as the full party document is at the moment of the save, I mean an embedded document of a copy of the Party document, which will not be affected by the updates done to the Party document in the future.
While I cannot change the Android Client, so I will still be getting only the ObjectId from it.
JSON example of what Android client will post: {"movementId":1, "relMovementId":4138, "_party":"58dbfe26194cfc5a9ec9b7c5"}
I'm confused now, and not sure if due to the way Android is posting the JSON, I need two schemas; one for the object received (i.e: with ObjectId and ref to Party) and a second one for the object persisted (i.e: with the schema referenced _party: Party.Schema) or if I could do something simpler as some populate prior to save... or what.
For the sake of closing this up:
I've implemented one of the approaches I had in mind while writing the question. Movement schema changed so that: _party: Party.Schema
When I get a POST to create a new movement I do a getById and use the result of that exec to populate the value as an embedded doc.

I cannot make a POST request to /questions/ID/answers 404 error

so I am making an API for creating questions and getting answers on the question id but whenever I use postman to create a POST request to answers.
Whenever I create a POST request to http://localhost:3000/api/questions/ID/answers it gives me a 404. I use node-restful package for creating this API and here is the Schema
// Dependencies
var restful = require('node-restful');
// Database
var mongoose = restful.mongoose;
var Schema = mongoose.Schema;
// Question Schema
var QuestionSchema = new Schema({
qTitle: {
type: String,
required: true
},
qBody: {
type: String,
required: true
},
created_at: {
type: Date
},
updated_at: {
type: Date
},
answers: [{
aTitle: {
type: String,
required: true
},
aBody: {
type: String,
required: true
},
created_at: Date,
updated_at: Date
}]
});
// Export the question schema
module.exports = restful.model('Questions', QuestionSchema);
If there is any errors or if you wish to see more code let me know!
Here is my routes
'use strict';
var express = require('express');
var router = express.Router();
var Question = require('../models/question');
Question.methods(['get', 'put', 'post', 'delete']);
Question.register(router, '/questions');
// Exports the router
module.exports = router;
According to the documentation for node-restful you need to turn on detail: true in a custom route like:
Question.route('answers', {
method:'post',
detail: true,
handler: function(req, res, next) {
// req.params.id holds the resource's id
res.send("I'm at /questions/:id/answers")
}
});
this is totally untested, and likely not completely correct since your model is complex and all the examples were pretty simple. But you definitely need a custom route. This little code snippet probably will set up a bunch of routes you don't want as well, but it should point you in the right direction.
I just took a quick look at the documentation here:
http://www.baugarten.me/node-restful/
I think you should add :id/answers like
Question.register(router, '/questions/:id/answers');

How to get data from existing MongoDB database?

I have a database on mlab and now I was starting a new Project and trying to simply get data from there.
The Database has only one collection called Article.
On my Node js project, using Mongoose, I created the Model for it:
var mongoose = require('mongoose');
var articleSchema = new mongoose.Schema({
title: { type: String, required: true },
body: { type: String }
});
var Article = mongoose.model('Article', articleSchema);
module.exports = Article;
The in my controller I just did this:
Article.find({}, function (err, articles) {
res.send(articles);
});
I should receive more than 300 articles but the response is just an empty Array.
I was wondering if I need to run a few more command in order to connect to the db correctly, but I don't know it...
If you want to fetch on an existing Article collection:
var articleSchema = new mongoose.Schema({
title: { type: String, required: true },
body: { type: String }
}, { collection : 'Article' });

Mongoose ODM - failing to validate

I'm trying to perform validation without saving. The API documentation shows that there's a validate method, but it doesn't seem to be working for me.
Here's my schema file:
var mongoose = require("mongoose");
var schema = new mongoose.Schema({
mainHeading: {
type: Boolean,
required: true,
default: false
},
content: {
type: String,
required: true,
default: "This is the heading"
}
});
var moduleheading = mongoose.model('moduleheading', schema);
module.exports = {
moduleheading: moduleheading
}
..and then in my controller:
var moduleheading = require("../models/modules/heading").moduleheading; //load the heading module model
var ModuleHeadingo = new moduleheading({
mainHeadin: true,
conten: "This appears to have validated.."
});
ModuleHeadingo.validate(function(err){
if(err) {
console.log(err);
}
else {
console.log('module heading validation passed');
}
});
You may notice that the parameters I'm passing in are called 'mainHeadin' and 'conten' instead of 'mainHeading' and 'content'. However, even when I do the call to validate() it never returns an error.
I'm obviously using validate incorrectly - any tips? The mongoose documentation is really lacking!
Thanks in advance.
Your validation will never fail because you've created default attributes for both mainHeading and content in your schema. In other words, if you don't set either of those properties, Mongoose will default them to false and "This is the heading" respectively - i.e. they will always be defined.
Once you remove the default property, you'll find that Document#validate will work as you initially expected. Try the following for your schema:
var schema = new mongoose.Schema({
mainHeading: {
type: Boolean,
required: true
},
content: {
type: String,
required: true
}
});

Resources