populating associations in mongodb - mongodb

I'm new to mean and mongodb and was trying to figure out how to populate my answers to my questions. I just changed the words in the platform that I'm learning (examples were posts and comments).
Here's the error message I'm getting.
/Users/joerigby/Documents/codingdojo/full mean/blacktest3/node_modules/express/lib/view.js:62
throw new Error('No default engine was specified and no extension was prov
^
Error: No default engine was specified and no extension was provided.
at new View (/Users/joerigby/Documents/codingdojo/full mean/blacktest3/node_modules/express/lib/view.js:62:11)
at EventEmitter.render (/Users/joerigby/Documents/codingdojo/full mean/blacktest3/node_modules/express/lib/application.js:569:12)
at ServerResponse.render (/Users/joerigby/Documents/codingdojo/full mean/blacktest3/node_modules/express/lib/response.js:961:7)
at /Users/joerigby/Documents/codingdojo/full mean/blacktest3/server/controllers/answers_c.js:53:12
at Query.<anonymous> (/Users/joerigby/Documents/codingdojo/full mean/blacktest3/node_modules/mongoose/lib/query.js:2112:28)
at /Users/joerigby/Documents/codingdojo/full mean/blacktest3/node_modules/mongoose/node_modules/kareem/index.js:177:19
at /Users/joerigby/Documents/codingdojo/full mean/blacktest3/node_modules/mongoose/node_modules/kareem/index.js:109:16
at process._tickCallback (node.js:355:11)
24 Aug 16:48:22 - [nodemon] app crashed - waiting for file changes before starting...
Below are my codes..
from answers_controller.js on server side
show: function(req, res){
console.log(req.params.id);
Question.findOne({_id: req.params.id})
.populate('answers')
.exec(function(err, question) {
res.render('question', {question: question});
});
}
}
from answer model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectID = require('mongodb').ObjectID;
var AnswerSchema = new mongoose.Schema({
answer: String,
description: String,
likes: {type: Number, default: 0},
created_at: {type: Date, default: Date.now },
_question: {type: Schema.ObjectId, ref: 'Question'}
});
mongoose.model('Answer', AnswerSchema);
from question model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectID = require('mongodb').ObjectID;
var QuestionSchema = new mongoose.Schema({
title: String,
description: String,
created_at: {type: Date, default: Date.now },
answers: [{type: Schema.Types.ObjectId, ref: 'Answer'}]
});
mongoose.model('Question', QuestionSchema);
Let me know if you need anything else to look at.
Thanks for your time.

The error is not with Mongo or Mongoose. Check the stack trace in your error message. The problem is from res.render. In order to use this method you must either configure express to have a default view engine (ejs, jade, etc.) or provide a file extension after 'question' so that it knows which template file to look for in order to render the HTML.
// in your main server file
// set default view engine
app.set('view engine', 'ejs');
// set view folder (where it looks for the template files
app.set('views', pathToViewFolder);
Now you can create a question.ejs file in the folder at pathToViewFolder.

Related

Problem with FreeCodeCamp's "MongoDB and Mongoose - Create a Model" Challenge

I am doing FreeCodeCamp's "MongoDB and Mongoose - Create a Model" challenge. I have submitted by code. However, I am getting this error:
Creating an instance from a mongoose schema should succeed
Here are my codes:
let mongoose = require('mongoose')
mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true });
let personSchema = new mongoose.Schema({
name: {type: String, required: true},
age: Number,
favoriteFoods: [String]
});
let Person = mongoose.model('Person', personSchema);
Have I made any mistake?
Since you are submitting this code to FCC server, you don't need to connect to db by your own. They must be having connections already made to db. You just have to provide the right implementation of Person model. IMO Since you had that line in your submission, code was breaking at that line and subsequent lines were not getting executed. Hence you were getting this error. Creating an instance from a mongoose schema should succeed
Try this -
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let personSchema = new Schema({
name: {type: String, required: true},
age: Number,
favoriteFoods: [String]
});
let Person = mongoose.model('Person', personSchema);
The following code worked for me after trying many different things suggested on different posts/blogs on the Internet.
require('dotenv').config();
//To-Do # 1: Install & Set up mongoose */
const mongoose = require('mongoose');
mongoose.connect(process.env.MONGO_URI);
//To-Do # 2: Create a Model
const personSchema = new mongoose.Schema({
name: { type: String, required: true },
age: Number,
favoriteFoods: [String]
});
const Person = mongoose.model('Person', personSchema);
I still could not find what was the problem as I tried to copy and paste exactly the code given in the solution to the problem suggested by free code camp and even that did not work. I was using replit and perhaps there must be some problem when the free code camp tests interact with the liver server of replit but some expert should answer the problem in detail to save time for other people.
It appears that the problem occurs because a code below is trying to redeclare the "Person" variable (After making it a const). If you look at the boilerplate code on Replit, there were some codes present there already and part of this code has the following:
let Person;
Simply commenting this line out worked for me.

Mongoose - Divide subdocuments using discriminators

If I have a model Attachment, which can be divided into 4 types: Link, YoutubeVideo, GoogleDriveFile, and GoogleDriveFolder, how can I use Mongoose to discriminate Attachment into these types, and allow them to be subdocuments in another schema; Post?
I've created the base Attachment model, and divided it into separate models using discriminators:
var AttachmentSchema = new Schema({
id: {type: String, required: true},
title: {type: String, required: true}
});
var Attachment = mongoose.model('Material', AttachmentSchema);
module.exports = {
DriveFile: Attachment.discriminator('GoogleDriveFile', new mongoose.Schema()),
DriveFolder: Attachment.discriminator('GoogleDriveFolder', new mongoose.Schema()),
Link: Attachment.discriminator('Link', new mongoose.Schema()),
YoutubeVideo: Attachment.discriminator('YoutubeVideo', new mongoose.Schema())
};
Now, in the Post schema, there should be an array of attachments, with varying types:
var Attachment = require('./attachment');
var PostSchema = new Schema(
text:{type: String},
attachments: [Material] // Could be Material.Link, Material.YoutubeVideo, etc
});
When I do this, I get an error saying "Undefined type Model at GoogleDriveFile. Did you try nesting Schemas? You can only nest using refs or arrays."
I don't know what this error means, and I can't find any docs explaining how to do this. Help?
Try doing the following:
var AttachmentSchema = new Schema({
id: {type: String, required: true},
title: {type: String, required: true}
});
var PostSchema = new Schema({
text: { type: String },
attachments: [ AttachmentSchema ] // Could be Material.Link, Material.YoutubeVideo, etc
});
var attachmentArray = PostSchema.path('attachments');
module.exports = {
Post: mongoose.model('Post', PostSchema),
DriveFile: attachmentArray.discriminator('GoogleDriveFile', new mongoose.Schema({})),
DriveFolder: attachmentArray.discriminator('GoogleDriveFolder', new mongoose.Schema({})),
Link: attachmentArray.discriminator('Link', new mongoose.Schema({})),
YoutubeVideo: attachmentArray.discriminator('YoutubeVideo', new mongoose.Schema({}))
};
The key is to NOT use a mongoose Model use the schema.path of the parent document schema as the base for your discriminators.
search for the term docArray on this link: Mongoose Discriminator documentation

inserting in mongo using express

i am trying to put data in the mongodb using express but it is storing blank always ...also it is not printing any console logs :
the url i am hitting after starting the sever is
http://localhost:3000/posts?title=test&link=http://test.com
and it is showing the below output:
{"__v":0,"_id":"562717b064002b1c2e697b33","comments":[],"upvotes":0}
router.get('/posts', function(req, res, next) {
console.log('reached ere '+req);
var post = new Post(req.body);
post.save(function(err, post){
if(err){ return next(err); }
res.json(post);
});
});
Post Scheme:
var mongoose = require('mongoose');
var PostSchema = new mongoose.Schema({
title: String,
link: String,
upvotes: {type: Number, default: 0},
comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }]
});
mongoose.model('Post', PostSchema);
You are calling your API as
http://localhost:3000/posts?title=test&link=http://test.com
which will send title and link to server as query parameters and not body parameters. So your req.body in this case would be an empty object. That is the reason no data in being saved in your posts collection.
You have two options here:
Change your API to save req.query in posts collection which you can do as follows:
Replace
var post = new Post(req.body);
with
var post = new Post(req.query);
Pass link and title as body parameters instead of query parameters.

Mongoose populate() returning empty array

so I've been at it for like 4 hours, read the documentation several times, and still couldn't figure out my problem. I'm trying to do a simple populate() to my model.
I have a User model and Store model. The User has a favoriteStores array which contains the _id of stores. What I'm looking for is that this array will be populated with the Store details.
user.model
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var UserSchema = new Schema({
username: String,
name: {first: String, last: String},
favoriteStores: [{type: Schema.Types.ObjectId, ref: 'Store'}],
modifiedOn: {type: Date, default: Date.now},
createdOn: Date,
lastLogin: Date
});
UserSchema.statics.getFavoriteStores = function (userId, callback) {
this
.findById(userId)
.populate('favoriteStores')
.exec(function (err, stores) {
callback(err, stores);
});
}
And another file:
store.model
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var StoreSchema = new Schema({
name: String,
route: String,
tagline: String,
logo: String
});
module.exports = mongoose.model('Store', StoreSchema);
After running this what I get is:
{
"_id": "556dc40b44f14c0c252c5604",
"username": "adiv.rulez",
"__v": 0,
"modifiedOn": "2015-06-02T14:56:11.074Z",
"favoriteStores": [],
"name": {
"first": "Adiv",
"last": "Ohayon"
}
}
The favoriteStores is empty, even though when I just do a get of the stores without the populate it does display the _id of the store.
Any help is greatly appreciated! Thanks ;)
UPDATE
After using the deepPopulate plugin it magically fixed it. I guess the problem was with the nesting of the userSchema. Still not sure what the problem was exactly, but at least it's fixed.
I think this issue happens when schemas are defined across multiple files. To solve this, try call populate this way:
.populate({path: 'favoriteStores', model: 'Store'})

mongoose schema multi ref for one property

How to write multi ref for one property of one mongoose schema, like this(but wrong):
var Schema = mongoose.Schema;
var PeopleSchema = new Schema({
peopleType:{
type: Schema.Types.ObjectId,
ref: ['A', 'B'] /*or 'A, B'*/
}
})
You should add string field to your model and store external model name in it, and refPath property - Mongoose Dynamic References
var Schema = mongoose.Schema;
var PeopleSchema = new Schema({
externalModelType:{
type: String
},
peopleType:{
type: Schema.Types.ObjectId,
refPath: 'externalModelType'
}
})
Now Mongoose will populate peopleType with object from corresponding model.
In the current version of Mongoose i still don't see that multi ref possible with syntax like you want. But you can use part of method "Populating across Databases" described here. We just need to move population logic to explicitly variant of population method:
var PeopleSchema = new Schema({
peopleType:{
//Just ObjectId here, without ref
type: mongoose.Schema.Types.ObjectId, required: true,
},
modelNameOfThePeopleType:{
type: mongoose.Schema.Types.String, required: true
}
})
//And after that
var People = mongoose.model('People', PeopleSchema);
People.findById(_id)
.then(function(person) {
return person.populate({ path: 'peopleType',
model: person.modelNameOfThePeopleType });
})
.then(populatedPerson) {
//Here peopleType populated
}
...