Mongoose Schema with SubDocument fields that are required - mongodb

Following Joe Eames tutorial, "Building AngularJS and Node.js Apps with the MEAN Stack" at Pluralsight, he demonstrates an example of a Mongoose Schema with document fields that are required, as follows:
var courseSchema = mongoose.Schema({
title: {type:String, required:'{PATH} is required!'},
featured: {type:Boolean, required:'{PATH} is required!'},
published: {type:Date, required:'{PATH} is required!'},
tags: [String]
});
I have created my own schema, with a sub-document that works:
......
skin : {styleNum : String, headerLogo: String},
......
However, I want the fields to be required and the subdocument is not an array (in Entity Framework it would be akin to an association, not a collection), so this is wrong:
......
skin : [
{styleNum : String, required:'{PATH} is required!'},
{headerLogo: String, required:'{PATH} is required!'}
]
......
What would be the correct syntax for creating an 'Entity Framework"-like association in a Mongoose Schema where both fields are required?

Nevermind, figured where my error was:
skin : {
styleNum: {type: String, required: '{PATH} is required!'},
headerLogo: {type: String, required: '{PATH} is required!'}
},

Related

join collections in mongodb [duplicate]

I coming from a sql background so writing queries in sql where I join tables is quite simple but I guess I am missing that in mongoose/mongodb
Basically I know the Subscriber_ID (which maps to a document in the User Collection)
I want to pull the project group, with all the projects that the user belongs to so if I was to write this in pseduo sql it would be like
Select
ProjectGroup.title,
Project.Title
FROM
ProjectGroup,
Project,
User
WHERE
User.id = req.body.subscriber_id
AND Project.subscriber_id = User.id
AND ProjectGroup.project_id = Project.id
There must be a way to do similiar joins in mongoose/mongodb because the type is mapping to a schema right?
My Schemas.....
Project Group Schema
var ProjectGroupSchema = new Schema({
title : String
, projects : [ { type: Schema.Types.ObjectId, ref: 'Project' } ]
});
Project Schema
var ProjectSchema = new Schema({
title : {type : String, default : '', required : true}
, subscribers : [{ type: Schema.Types.ObjectId, ref: 'User' }]
});
User Schema
var UserSchema = new Schema({
first_name : {type: String, required: true}
, last_name : {type: String, required: true}
});
Thank you!
You are just one step away!
Project Group Schema:
var ProjectGroupSchema = new Schema({
title : String
});
Project Schema:
var ProjectSchema = new Schema({
title : {type : String, default : '', required : true},
group : {type: Schema.Types.ObjectId, ref: 'ProjectGroup' },
_users : [{type: Schema.Types.ObjectId, ref: 'User' }]
});
User Schema:
var UserSchema = new Schema({
first_name : {type: String, required: true},
last_name : {type: String, required: true},
subscribing : [{type: Schema.Types.ObjectId, ref: 'Project' }]
});
Then you can do the following:
user.findById(req.userId)
.populate('subscribing')
.exec(function(err, user){
console.log(user.subscribing);
})
Or:
project.find({
subscriber : req.userId
})
.populate('subscriber')
.populate('group')
.exec(function(err, projects){
console.log(projects);
})
There are no joins in Mongodb. This question I think is a good reference:
MongoDB and "joins"
To summarize, different strategies have to be adopted with mongodb for problems that would be addressed via joins in relational DBs. I would say you mainly end-up doing one of these two things:
Embedding: You embed information in a single document that would in a relational DB be distributed amongst different tables.
Joining information client-side: When you need to use information from several places, you query many times and then put the pieces together in your client.

How to write a Mongoose query for items whose IDs are not in an array

I have two models: Event and People.
schemas.event = new mongoose.Schema({
eventId: Number,
name: {type: String},
size: Number,
location: {type: String},
date: {type: Date},
people: [{type: mongoose.Schema.Types.ObjectId, ref: models.Person}],
note: {type: String}
});
and People
schemas.person = new mongoose.Schema({
firstname: {type: String},
lastname: {type: String},
age: Number,
email: {type: String},
gender: {type: String}
});
Given a certain event, I want to do a Query using Mongoose, to find all the people not already registered for this event.
Something like
models.Person.find({not in event.people});
The tricky thing for me is, that event.people is not an array of IDs, but rather it is an array of Objects that look like
[
{
"$oid": "558ced061d35bd072e7b5825"
},
{
"$oid": "558ced061d35bd072e7b58a0"
},
{
"$oid": "558ced061d35bd072e7b58c6"
}
],
Is there any way to simply make this query?
Firstly, you need to create an array of the ObjectId's by using the native JavaScript method map() which creates a new array with the results of calling a provided function on every element in this array:
var mongoose = require("mongoose");
var arr = event.people.map(function(item){ return mongoose.Types.ObjectId(item["$oid"])});
You can then query the collection using that as the $nin operator expression:
models.Person.find({"_id": { "$nin": arr}}).exec(callback);
Look into the following operators:
$not - http://docs.mongodb.org/manual/reference/operator/query/not/
$in - http://docs.mongodb.org/manual/reference/operator/query/in/
$nin - http://docs.mongodb.org/manual/reference/operator/query/nin/

MongoDB using mongoose for populate

I am having collection1 with one of the column as ref of collection2. Now i want to populate(join) collection1 and collection2 with some condition on collection2 fields. Is it possible?
What i want to do is
models.Encounter
.where('practice').equals(practice)
.populate({
path:'chart',
match:{firstName:{ $regex: new RegExp(Name.toLowerCase(), 'i') }},
select:'firstName lastName'})
.populate('provider', 'firstName lastName')
.populate('signedBy', 'firstName lastName')
.sort('-date')
.limit(100)
.exec(function (err, encounters) {})
Here charts is collection and for me match is not working..Where Name comes from jade engine. null values are coming for firstname
Practice Schema:
The schemas are
var practiceSchema = mongoose.Schema({
name: String,
internalName: String,
address: addressSchema,
phone: String,
taxId: String
});
Chart Schema:
var chartSchema = mongoose.Schema({
created: Date,
updated: Date,
practice: {type: mongoose.Schema.ObjectId, ref : 'practices', required: true},
mrn: String,
firstName: String,
lastName: String,
emailWork: String,
phoneHome: String,
phoneMobile: String,
dob: Date,
married: Boolean,
smoker: Boolean
});
Now i want to get data from Encounters by populating charts and also charts.firstName == 'XYZ' and charts.lastName == 'ABC'.. I have done this by getting all data from encounters and then applying filter on charts. But it is taking too much of time..

Mongoose retrieval of info from multiple collections

I'm building a resume building app with Mongoose and Express. I set my models up so that education and work experience are both in their own collections. something similar to this:
"degree" : "BA",
"major" : "Econ",
"minor" : "Bus. Admin",
"startDate" : ISODate("2013-12-31T00:00:00Z"),
"endDate" : ISODate("2013-01-01T00:00:00Z"),
"user" : "example#gmail.com",
"created" : ISODate("2013-10-15T19:32:09.357Z"),
"_id" : ObjectId("525d9839ddc8bf7855000001"),
"school" : {
"name" : "university of alabama",
"loc" : "austin, tx"
},
"__v" : 0
I have a reference to the _id of the User model in the "user" value. my User model looks like so:
var schema = mongoose.Schema({
_id: {type: String, lowercase: true, trim: true, validate: validEmail }
, name: { first: String, last: String}
, salt: {type: String, required: true}
, hash: {type: String, required: true}
, edu: [{type: String, ref: 'Education'}] });
When I try to populate the edu section of my User model with information from the education model it's not finding anything.
My query is this:
var query = User.findById(user)
.populate('edu');
So how would I properly allow my User model make references to the education model so that I can send info from both to a view? Could I populate to fields like that?
Any advice would be mega helpful. I'll be scouring the docs, google and trying random things that kind of make sense in the mean time.
Thank you.
You need to use the mongoose.Schema.Types.ObjectId type in order for populate to work properly.
var schema = mongoose.Schema({
_id: {type: String, lowercase: true, trim: true, validate: validEmail }
, name: {first: String, last: String}
, salt: {type: String, required: true}
, hash: {type: String, required: true}
, edu: [{type: mongoose.Schema.Types.ObjectId, ref: 'Education'}] });
side note:
you don't need to define _id as you get that automatically and it should not be an email. Use a separate email field for that.

Mongoose adds _id to all nested objects

When creating a document with nested objects (e.g. an array of objects), each object is given its own _id. For example, my schema looks like this:
mongoose = require "mongoose"
Schema = mongoose.Schema
schema = new Schema
name:
type: String
required: true
unique: true
trim: true
lists: [
list:
type: Schema.Types.ObjectId
required: true
ref: "List"
allocations: [
allocation:
type: Number
required: true
]
]
createdAt:
type: Date
default: Date.now
updatedAt:
type: Date
# Ensure virtual fields are serialised.
schema.set "toJSON",
virtuals: true
exports = module.exports = mongoose.model "Portfolio", schema
Every object in the lists array is given an _id, as is every allocation object in the lists.allocations array, when documents are eventually created. This seems like overkill and bloats the document, but is there a reason MongoDB (or Mongoose) needs the document to contain this additional information? If not, I'd like to prevent it from happening so that the only _id is on the root document.
Furthermore, Mongoose automatically creates a virtual id for _id, which I need because my client code expects a field id. This is why I'm having virtuals returned with JSON. However, because there are _id fields all throughout the document, not just at the root, this virtual duplicates all of them. If there is no way to prevent the additional _id fields, how can I get a virtual to only apply only to the root document _id? Or if there is a better way to do what I'm trying to do with it, what would it be?
I have figured out a way to solve both issues with the same technique: by using explicit schemas for each nested object type and setting their _id and id options to false. It seems that when nesting objects that you define "inline", Mongoose creates schemas for each of those objects behind the scenes. Since the default for a schema is _id: true and id: true, they will get an _id as well as have a virtual id. But by overriding this with an explicit schema, I can control the _id creation. More code, but I get what I want:
mongoose = require "mongoose"
Schema = mongoose.Schema
AllocationSchema = new Schema
allocation:
type: Number
required: true
,
_id: false
id: false
mongoose.model "Allocation", AllocationSchema
ListsSchema = new Schema
list:
type: Schema.Types.ObjectId
required: true
ref: "List"
allocations: [AllocationSchema]
,
_id: false
id: false
mongoose.model "Lists", ListsSchema
PortfolioSchema = new Schema
name:
type: String
required: true
unique: true
trim: true
lists: [ListsSchema]
createdAt:
type: Date
default: Date.now
updatedAt:
type: Date
#neverfox thanks for info, I just adding the code for Nodejs
var _incidents = mongoose.Schema({
name : {type : String},
timestamp: {type : Number},
_id : {id:false}
});
_schema = mongoose.Schema({
_id: {type: String, required: true},
user_id: {type: String, required: true},
start_time: {type: Number, required: true},
incidents : [_incidents],
});