Using multiple models for collections in mongoDB mongoose - node.js

Im making a translation app, I want to have a new collection for each language.
When I go to /norwegian for instance I want to find from the collection of the same name.
How is this acheived?
at the moment I'm serving it like this.
// MONGOOSE/MODEL CONFIG
var norskSchema = new mongoose.Schema({
english: String,
phonetic: String,
category: String,
cat_id: Number,
lang: String
}, {collection: 'norwegian'});
var Norsk = mongoose.model("norwegian", norskSchema);
then calling
app.get('/norwegian', function(req, res){
Norsk.find(function(err, data) {
res.render('index', {data: data});
}).sort({ cat_id: 1});
});
Can I remove the collection object at the bottom of my schema and then call the same above adding a language as dot notation?
Trans.norwegian.find(function(err, data) {});
Trans.polish.find(function(err, data) {});
etc...
Thanks in advance.

As mentioned by #JohnnyHK you can do something like the following:
app.get('/norwegian', function(req, res){
mongoose.model('norwegian').find(function(err, data) {
res.render('index', {data: data});
}).sort({ cat_id: 1});
});
this should query with respect to a model without having to explicitly import the model .js object

Related

Mongoose NodeJS Schema with array of ref's

I know there is allot's of answers about it but still I didn't quite get the idea.
I have CourseSchema:
const CourseSchema = new Schema({
course_name: String,
course_number: {type: String, unique : true },
enrolledStudents:[{
type: mongoose.Schema.Types.ObjectId,
ref: 'Student' }]
});
And a StudentSchema:
const StudentSchema = new Schema({
first_name: String,
last_name: String,
enrolledCourses:[{
type: mongoose.Schema.Types.ObjectId,
ref: 'CourseSchema'
}]
});
I want to reffer enrolledStudents at CourseSchema with a student, and enrolledCourses at StudentSchema with a course.
router.post('/addStudentToCourse', function (req, res) {
Course.findById(req.params.courseId, function(err, course){
course.enrolledStudents.push(Student.findById(req.params.studentId, function(error, student){
student.enrolledCourses.push(course).save();
})).save();
});
});
but when posting I get an error:
TypeError: Cannot read property 'enrolledStudents' of null
Ok so after readying Query-populate I did that:
router.post('/addStudentToCourse', function (req, res) {
Course.
findOne({ _id : req.body.courseId }).
populate({
path: 'enrolledStudents'
, match: { _id : req.body.studentId }
}).
exec(function (err, course) {
if (err) return handleError(err);
console.log('The course name is %s', course.course_name);
});
});
And when i'm hitting POST on postman I get on the console:
The course name is intro for cs
but it is loading for ever and later on console I get:
POST /courses/addStudentToCourse - - ms - -
You are missing the populate instruction. For example:
see more about it here
Course.
findOne({ courseId : req.params.courseId }).
populate('enrolledStudents').
exec(function (err, course) {
if (err) return handleError(err);
console.log('The course name is %s', course.name);
});
It is working by using the ref field that "knows" how to populate withput using the push syntax. it is like a foreign key population.
Just call the populate method on the query and an array of documents will be returned in place of the original _ids. you can learn more on the internals of the populate methods in the official docs

Using $or in a FindOne query - MongoDB

UPDATE: Changed if (!result.length) to if (!result) as I'm using .findOne and that seems to be working so far. If you spot anything else that can be improved within the code snippet that would be awesome!
Just starting to learn Node JS and MongoDB (using Mongoose) so excuse me if I'm totally out of context.
Im trying to find a row in my MongoDB with the following query:
exports.findById = function(req, res) {
var id = req.params.id;
Team.findOne({'teamid':id, $or:[{'creator':req.user.id}, {userlist: { $in : [req.user.id]}}]}, function(err, result) {
if (err) console.log(err);
if (!result.length)
res.redirect('/');
else
res.render('team', { team : result.teamid });
});
};
I want to retrieve a row that has the field teamid equal to id as well as to check if the field creator is equal to req.user.id OR if req.user.id is in the userlist field. I am expecting only one result from the above query.
Note that this query works just fine, but I just need to look inside the userlist array:
Team.findOne({'teamid':id, 'creator':req.user.id}, function(err, result) {...
And finally the Team schema
var Team = new Schema({
team_name: { type: String, required: true, trim: true},
teamid: { type: String },
creator: String,
created_at: Date,
userlist: Array
});
Any help to figure out what's the problem is greatly appreciated!

nodejs + mongoose - how to use forEach in nodejs

I'm still learning about node.js and mongodb. I'm trying to write simple app with nodejs and mongoose. My mongoose schema:
var todoSchema = new Schema({
task: String,
description: String,
date: Date,
status: String,
checklist: Boolean,
pic: String
});
I have collection named todos I'm trying to get the content of todos using this code:
apiRoutes.route('/todos/detail')
.get(function(req, res){
Todo.distinct( "pic" ).each(function(doc){
Todo.find({"pic": doc.pic}, function(err, todo){
if (err)
res.send(err);
var finalResult = [];
finalResult.push(todo);
res.send(finalResult);
});
});
});
But I got this error:
Object #<Query> has no method 'each'
Any idea to solve this? Really appreciate for the help.
From what I gather in your question, you don't necessarily need the loop since with the distinct pics array you are iterating over, you are using it to query the collection for each pic, which is
essentially equivalent to just querying the whole collection as sending the resulting array of documents returned from the query:
apiRoutes.route('/todos/detail').get(function(req, res){
Todo.find({"pic": { "$exists": true }}, function(err, todos){
if (err) res.send(err);
res.send(todos);
});
});
Unless you want to get a distinct list of pics, get the todo items with those pics you could try the following approach:
apiRoutes.route('/todos/detail').get(function(req, res){
Todo.find().distinct('pic', function(error, pics) {
// pics is an array of all pics
Todo.find({"pic": { "$in": pics } }, function(err, todos){
if (err) res.send(err);
res.send(todos);
});
});
});
For starting you should try with .forEach() instead of .each() first :)
Here you can see the forEach doc.

How to replace the ObjectId ref. with with the actual object from MongoDB (idealy on the server side)?

Here is the schema of the principal object:
var newsSchema = new Schema({
headline: String,
paragraph: String,
imgURI: String,
imgThumbURI: String,
imgCaption: String,
addedOn: Date,
addedBy: {
type: ObjectID,
ref: 'usr'
}
});
var News = mongoose.model('news', newsSchema);
...and the schema for the addedBy:
var usr = new Schema({
username: String,
avatar: {
type: ObjectID,
ref: 'avtr'
},
href: String
});
var UserModel = mongoose.model('usr', usr);
So far so good. All works. Then in Angular client I retrieve a news object, but the addedBy value is not the desired object, but an ObjectId:
{
"headline":"Shocking news from the Neverland!",
...
"addedBy":"520e9aac9ca114914c000003", // <-- the offender!!
"addedOn":"2013-08-16T21:33:32.294Z",
"_id":"520e9aac9ca114914c000001",
"__v":0
}
When I want an object like this:
{
"headline":"Shocking news from the Neverland!",
...
"addedBy":{
"username":"Peter"
"avatar":{
"src":"../images/users/avatars/avatar1.png",
"ststus":"happy"}
}
"addedOn":"2013-08-16T21:33:32.294Z",
"_id":"520e9aac9ca114914c000001",
"__v":0
}
So yes, I want to all (no mater how deeply) nested ObjectId's be replaced with their respective objects from the DB, before the principal object is sent to the angular client. The API I am building is deep and complex and it would be nice if the angular client could to receive from my Express server an object which is ready to be thrown into a scope.
How do I change the following '/news' route:
app.get('/news', function(req, res, next){
News.
find().
exec(function(err, nws){
if(err) {res.writeHead(500, err.message)}
res.send(nws);
});
});
to accomplish just that, so I can fully access the complete (nested) object from angular like this:
angular.module('App', ['ngResource'])
.controller('NewsCtrl', function($scope, $resource){
var News = $resource('/news');
var news = News.query();
$scope.news = news;
});
and then on the website access the api like this:
<img class="avatar-img" src="{{ news[0].addedBy.avatar.src }}">
I very much appreciate your time,
cheers
Jared
As #WiredPrairie said, you need to use the populate function Populate Mongoose Documentation
Your query should look like this:
app.get('/news', function(req, res, next){
News.
find().
populate("addedBy").
exec(function(err, nws){
if(err) {res.writeHead(500, err.message)}
res.send(nws);
});
});
There are plenty of different things that you can do with populate, for example to bring only the username field of the "addedBy" document, you can do
populate("addedBy","username")
or if you don't want bring one specific field, doing something like this:
populate("addedBy","-username")

How to query another collection on callback of first query.

So I have a few mongoose schema's defined.
var partSchema = mongoose.Schema({
name: String,
system: String,
team: Array,
quantity: Number,
});
var part = mongoose.model('part', partSchema);
var peopleSchema = mongoose.Schema({
name: String,
pass: String,
role: String,
parts: Array
});
var people = mongoose.model('people', peopleSchema);
And I want to send queries based on these schemas, and more, to the user. As such...
app.get('/', function(req, res){
people.find(function(err, persons){
if (err) return handleError(err);
console.log(persons);
parts.find(function(err, things){
res.render('in', { user: req.session.user, people:persons, parts:things });
});
});
});
To remain asynchronous, I would have to nest these calls, right? And I cant nest these calls, because "parts" is no longer defined. I'm wondering if I could do this, and how would I do it? Sorry if it's a noob question, but I've looked this up for days, and haven't seemed to find a solution. Thanks!
The variable name of your 'part' model is part, not parts. So it should be:
app.get('/', function(req, res){
people.find(function(err, persons){
if (err) return handleError(err);
console.log(persons);
part.find(function(err, things){ // <-- Changed on this line
res.render('in', {user: req.session.user, people:persons, parts:things});
});
});
});

Resources