Why is the find method not working in Mongoose - node.js

I am working on a express app with mongoose.
the .find method is working in other route but inside my blogs route, it is not working.
Here is my mongoose model:
const mongoose = require('mongoose');
let BlogSchema = new mongoose.Schema({
title: {type: String, unique: true, required: true},
body: {type: String},
category: String,
permalink: String,
date: {type: Date, default: Date.now},
image: {type: String},
imageId: String,
tags:[{type: String}],
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}
});
let Blog = mongoose.model('Blog', BlogSchema);
module.exports = Blog;
and here is my router.get :
//SHOW ROUTE
router.get('/blog/:category/:permalink', (req,res)=>{
console.log(req.params) //{ category: 'travel', permalink: 'why-travel-to-places' }
Blog.find({category: req.params.category,permalink: req.params.permalink}, (err, foundPost)=> {
if (err){
console.log(err)
} else {
console.log(foundPost) // []
res.render('blog/show', {post: foundPost});
}
});
});
As you can see, I console.log req.params and foundPost .
req.params result is { category: 'travel', permalink: 'why-travel-to-el-nido' } and foundPost is an empty array []
Now I looked at mongo using db.blogs.find({category: "travel"}).pretty() and it found it. But inside my show route ,it is not finding it?
I looked up on other questions related to my problem and someone said that perhaps it has a problem with schema, but in my case, it's not.
my .find() is working in in other routes but in it's not working in this route.
Did I miss something, please help. Thank you

I'm pretty sure that the .find() is working correctly, but is not finding any document in the database with that query criteria. Note that in the route code you are querying { category: 'travel', permalink: 'why-travel-to-el-nido' }, i.e that the matched Blog document must have the fields category: 'travel' AND permalink: 'why-travel-to-el-nido', but when you look at Mongo using db.blogs.find({category: "travel"}).pretty() you are only looking for Blog documents that have {category: "travel"}, but no restriction for the permalink field.
Please, search again in Mongo using db.blogs.find({category: "travel", permalink: "why-travel-to-el-nido"}).pretty() to simulate the same query from the route, and see if you can find any document that matches that criteria.
My guess is that you won't find any, so the mongoose .find() is returning an empty array, meaning "no matches".
Edit: I just saw the comment from Neil Lunn, and it might be possible that the mongoose configuration is not pointing to the right database. Follow his instructions to make sure you are querying to the collection you want.

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.

Mongoose query in an Object

Question, I got a schema using mongoose which created an Object. I don't know how to query the author id which will return the list of the object under the author Id
var mongoose = require("mongoose");
var bookedSchema = new mongoose.Schema({
origin: String,
destination: String,
author: { id: { type: mongoose.Schema.Types.ObjectId, ref: "User"}, username: String},
Date: {type: Date, default: Date.now}
});
module.exports = mongoose.model("Booked", bookedSchema);
On my route I have query find({}) i want to query the author id instead of {} and it will return the list of object under the author ID. i tried the findById(author:{id:req.user._id}) but it returned null answer. any ideas how to do that. Thank You!
router.get('/myAccount', function(req, res){
Booked.find({}).exec(function(err, booked){
if(err){
console.log(err);
// res.redirect('back');
}else{
console.log(booked)
res.render('accounts/myAccount', {booking:booked});
}
});
});
you should use .populate() for refered documents to populate them.
change this:
Booked.find({}).exec(function(err, booked)
to:
Booked.find({}).populate('author').exec(function(err, booked)
or if you need to find a document by the refered author id you can use this:
Booked.find({}).populate({
path: 'author',
match: { id: { $eq: req.user._id }}
}).exec(function(err, booked)

Retrieve Array in Subdocument MongoDB

I have a Users model structure somewhat like this:
const userSchema = new mongoose.Schema({
email: { type: String, unique: true },
password: String,
todosDo: [models.Do.schema],
}
And the child "Do" schema somewhat like this (in a different file):
const doSchema = new mongoose.Schema({
name: {type: String, default : ''},
user: {type: mongoose.Schema.ObjectId, ref: 'User'},
createdAt: {type : Date, default : Date.now}
});
And I'm trying to figure out how to retrieve the todosDo array for the signed in user. This is what I've got so far:
// Get all "Do" todos from DB
// Experimenting to find todos from certain user
User.findById(req.user.id, function(err, user){
if(err){
console.log(err);
} else {
doTodos = user.todosDo, // this obviously doesn't work, just an idea of what I was going for
console.log(doTodos);
finished();
}
});
Am I referencing the child/parent wrong or am I just not retrieving the array right? Any help is greatly appreciated!
As far I guess you may want to edit as raw js objects so you need to use lean() function. without using lean() function user is mongoose object so you can't modify it.
can try this one:
User.findById(req.user.id)
.lean()
.exec(function (err, user) {
if(err){
console.log(err);
return res.status(400).send({msg:'Error occurred'});
}
if(!user) {
return res.status(400).send({msg:'User Not found'});
}
doTodos = user.todosDo;
console.log(user.todosDo); // check original todos
console.log(doTodos);
return res.status(200).send({doTodos : doTodos }); // return doTodos
});
and to refer child schema in parent schema from different model you can access a Model's schema via its schema property.
say in doSchema.js file
const doSchema = new mongoose.Schema({
name: {type: String, default : ''},
user: {type: mongoose.Schema.ObjectId, ref: 'User'},
createdAt: {type : Date, default : Date.now}
});
module.exports = mongoose.model( 'DoSchema', doSchema );
in user.js file
var DoModel = require('./doSchema');// exact path
const userSchema = new mongoose.Schema({
email: { type: String, unique: true },
password: String,
todosDo: [DoModel.schema],
}
Thanks for your help everybody! My problem was that I needed to push all the newly created todos in the post route to todosDo, so then I could retrieve them at the get route. Everything's working now!

Displaying content from different mongoose tables on one view

I'm a (relatively inexperienced) Java EE developer who is looking to learn node.js. I'm working with the express framework, mongodb, and the mongoose framework. I've been working on building a simple blog site (just for practice) with an mvc like architecture. It would have would have 4 mongodb collections: post, image, user, comment. The basic Schemas are as follows:
postSchema = mongoose.Schema({
id: Number,
dateCreated, {type: Date, default: Date.now}
title: String,
content: String
});
var Post = mongoose.model('Post', postSchema);
imageSchema = mongoose.Schema({
id: Number,
postId: Number,
path: String
});
var Image = mongoose.model('Image', imageSchema);
userSchema = mongoose.Schema({
id: Number,
username: String,
password: String,
email: String
});
var User = mongoose.model('User', userSchema);
commentSchema = mongoose.Schema({
id: Number,
postId: Number,
userId: Number,
dateCreated: {type: Date, default: Date.now},
content: String
});
var Comment = mongoose.model('Comment', commentSchema);
I want to be able to show a post, an image, comments, and user info all on one page. My issue is that I can't quite figure out how retrieve and send all this data in an asynchronous way. This seems to be what most of the examples I have found do (not necessarily all in one file):
app.get('/', function(res, req) {
Post.findOne(function(err, post) {
if (err) return res.send(500);
res.render('index', post);
});
});
This wouldn't work for me because I would info from the image, comment, and user collections as well. Is there an asynchronous way to do this? If not is there a way to reconfigure what I have so that it could be asynchronous? (I'm trying to get a feel for asynchronous programming.)
Thanks in advance!
Simples way to do this as-is would be to use promises and perform simultaneous async operations:
Post.findOne(id).then(post => {
let postId = post.id;
return Promise.all([
Comments.find({postId}),
Images.find({postId}),
// Not sure what query you need here
User.find(),
post,
]);
}).then(data => {
let [comments, images, users, post] = data;
res.render('index', {comments, images, users, post});
});
In your index template you would have an object with the four properties.
You can perform simultaneous async operations without promises, but I'll leave that for someone else to talk about. I would prefer to work with promises.
Mongoose will also allow you to use other schema definitions as data types as in:
commentSchema = mongoose.Schema({
id: Number,
postId: Post,
userId: User,
dateCreated: {type: Date, default: Date.now},
content: String
});
In this case you can use .populate after some queries in order to perform another query under the hood -- e.g. get the post data for a comment.
Since you are using MongoDB -- a NoSQL Database -- I would look into denormalizing the data and keeping it flat. Firebase, which stores data in a similar structure has a great article on how to store and use denormalized data

Nodejs, Mongoose and Jade get no data from Database

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

Resources