Defining a property on mongo schema referencing another schema plus extra fields - javascript

I am trying to define a mongo Schema using mongoose. I need to create an 'Event Schema' in which users are referenced. So I am populating the 'users' field with the referenced ObjectId of the user Schema. However I also need to add some extra fields on that user property which are specific to the event. So something like as follows:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var EventSchema = new Schema({
name: String,
date: Date,
users: [{
profile: {
type: Schema.ObjectId,
ref: 'User'
},
RankNumber: Number,
bibNumber: Number
}],
published: Boolean
});
mongoose.model('Event', EventSchema);
However this doesn't work. I am not sure the best way to do what I am trying to achieve.
So if I have a constructor function such as:
function User(bib, rank, profile) {
this.bib = bib;
this.rank = rank;
this.profile = profile;
}
and then I call that constructor and pass in a user id as the profile property, MongoDB will create a new id field. I get a JSON response like this:
{
"name": "Event name",
"_id: "mongoid",
"users": [
{
"bibNumber": "278",
"rankNumber": "21",
"profile": "users mongo _id number",
"_id": "a new mongo _id"
}
]
}
I need to populate the profile field. But the following won't work:
Event.find().populate('users').exec(function (err, events) {....

You have to use, as I said in the comments:
Event.find(...).populate('users.profile').exec(...);

Related

Populating an Object with Information from a Child Object with Different Model (JS/Mongoose)

Here is what I have. I created a project model that references a user model for an array of members.
var ProjectSchema = new mongoose.Schema(
{title: {
type: String,
required: true
},
members: [
{user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'users'
}
}],
});
User Schema (I have code that creates a model from both of these schemas)
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
}
});
In a separate file, I want to export the JSON of a found project and include the information of the users in the members array, but I am not sure how to do that. This is the code I have right now.
const project = await Project.findById(req.params.proj_id).populate(
'members'
);
res.json(project);
It has no trouble finding the project but the only information I can get on the members is their id. I tried using for loops to gather the information from members separately using the id that I can get from the project, but the code gets messy and I am hoping to find a simpler way to do it.
You can use mongoose populate query to get all members associated with a project. It should populate array of objects users associated to a project. You should be doing something like this:
const project = await Project.findById(req.params.proj_id)
await project.populate('members').execPopulate()
console.log(project.members)
Mongoose docs for the reference: Populate
You can give the model to your mongoose populate.
const project = await Project.findById(req.params.proj_id)
.populate({
'members',
model: UserModel
})
.exec()
res.json(project);
keep in mind you've to create UserModel just like
const UserModel = mongoose.model('User', userSchema);

How do I add new keys to a Mongoose Schema?

I recently started developing an app for my senior project which requires me to use some type of database. For that I decided to go with Mongoose since it is noSQL and slightly easier to pick up.
So, fast forward and I run into a problem where I can't figure out how to edit an already existing Schema and add new keys into it.
For example, I have this Schema which represents a post(think Tweets or Facebook posts) that holds:
A string that holds the body of the post
The id of the user that created the post
The Date of when the post was created
My code for that is:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const PostsSchema = new Schema({
Value: {
type: String,
required: true
},
User: {
type: Schema.Types.ObjectId,
ref:'users'
},
Date: {
type: Date,
default: Date.now
}
});
// Create collection and add schema
mongoose.model('posts', PostsSchema, 'posts');
What I want now is to access that schema in some way and add a new key to it using something similar to maybe
PostsSchema.add({Private: { default: false}});
Meaning that, now the schema in the database will look something like:
{
"_id": {
"$oid": "1831g98af21n9s5u7s9ccchj5"
},
"Value": "Beautiful day outside, can't wait to go jogging!",
"User": {
"$oid": "9a79ab143lbk9lk55wq327oi3226m"
},
"Date": {
"$date": "2018-10-29T01:28:44.408Z"
},
"Private": "false"
"__v": 0
}
So back to my question, is there any way to do this? Or if you have a link to documentation of such methods I would greatly appreciate it. Thank you Greatly!
Just add the field to the schema with a default:
const PostsSchema = new Schema({
Value: {
type: String,
required: true
},
User: {
type: Schema.Types.ObjectId,
ref:'users'
},
Date: {
type: Date,
default: Date.now
},
Private: {type: Boolean, default: 'false'}
});
Since you have a default any new record will have it as well as any new instance of an old model saved before you added the private field.
If you really need more dynamic approach the usual recommendation is using Mixed Type with all the pluses and minuses that come with it.

Nested elements in mongoose modelling

I have to create a database in this format:
I have tried to do it like this :
var mongoose = require("mongoose")
, Schema = mongoose.Schema;
var categorySchema = new Schema({
_id: String,
subcategory: {
type: Schema.Types.ObjectId,
ref: "Subcategory"
},
id: String,
name: String,
page_description: String,
page_title: String,
parent_category: String,
c_showInMenu: Boolean
});
module.exports = mongoose.model("Category", categorySchema);
And I did the same for every subcategory, but I named them "Subcategory" and "SubsubCategory". I'm pretty much a newbie, I've read the documentation on mongoose and I've also followed an online course. I feel like I know something, but I don't understand it properly or that my logic behind it is wrong.
Also, I've managed to find this about recursive elements in Schemas, but I don't fully understand it and I don't know how to implement it to my database: Recursive elements in Schema : Mongoose modelling
I checked your code and collection image.
Here's what you are doing wrong.
You don't need to declare _id field, it's auto-generated.
Keep the column names same as they are in the given collection image.
This should be your schema declaration. Note that, this schema is for the whole collection and not just for categories array.
var mongoose = require("mongoose"),
Schema = mongoose.Schema;
var mainSchema = new Schema({
categories: [ {
id: String,
image: String,
name: String,
page_description: String,
page_title: String,
parent_category_id: String,
c_showInMenu: Boolean
}]
});
This is just an example of the schema, please add necessary changes to it.

Simple Mongodb embedded database structure

i want to build a Mongodb database (Mongoose/Node.js) structure but i face a problem right now. i have two entities. Users and Books and i want to use embedded system(because of lack of joins in mongodb). And my problem is that which of this entities shpuld be an inner value to other.
For example i wiil face this two type of query in my app:
1- Books of an specific user
2- Users of an specific book
Now, Books should be a inner value for Users or contrariwise?
i can do this two:
Users schema:
var schema = new mongoose.Schema({
use_name: String,
user_family: String,
user_books: { type: Schema.Types.ObjectId, ref: 'books' }
});
Or this:
Books Schema:
var schema = new mongoose.Schema({
book_name: String,
book_lang: String,
book_user: { type: Schema.Types.ObjectId, ref: 'users' }
});
which is better? which is standard approach?
if i use both of them, when saving i have to do two save operation. if i has a large database with a lots of collections its gets worse that this...
after a lot of research i find out i have to use embedded system rather that using relation like collections to connect entities to each other, because Mongodb doesn't support joins and has poor support of things like this. embedded system is the correct way for a NoSql database like Mongodb?
Firstly, there's a minor correction that your user_books needs to be an array [].
Secondly, you should only reference one schema into another, otherwise you'll have to add unnecessary complexity in keeping them in sync.
So here's what your schemas should look like:
var UserSchema = new mongoose.Schema({
use_name: String,
user_family: String,
user_books: [{ type: Schema.Types.ObjectId, ref: 'books' }]
});
var BookSchema = new mongoose.Schema({
book_name: String,
book_lang: String,
});
Now "to fetch users that reads an specific book", you'll query like this:
UserSchema.find({ user_books: book._id })
which will give you all users that have BOOK_ID as (at least) one of their books.
If that's all, I guess you don't need population at all then.
Updated on the issue with $elemMatch query not working:
So as it turned out, we don't actually need $elemMatch with referenced docs array, since it's a simple array of _ids.
user // =>
{
_id: 56351c611ca0d2e81274100a
name: ...
books: [56351c611ca0d2e81274100b, 56351c611ca0d2e81274100c, ...]
}
$elemMatch works with array of objects, and would've been in the case of embedded doc:
var BookSchema = new mongoose.Schema({
book_name: String,
book_lang: String,
});
var UserSchema = new mongoose.Schema({
use_name: String,
user_family: String,
user_books: [BookSchema]
});
Since in this case the document would be like this:
user // =>
{
_id: 56351c611ca0d2e81274100a
name: ...
books: [
{ // each book here has an _id:
_id: 56351c611ca0d2e81274100b,
// this is what `$elemMatch: {_id:` would match for
name: ...
// you could do `$elemMatch: {name:`
lang: ...
// or `$elemMatch: {lang:`
}, {
_id: 56351c611ca0d2e81274100c,
name: ...
lang: ...
}, ...
]
}
This is where $elemMatch query would be needed.
UserSchema.find({ user_books: {$elemMatch: {_id: book._id } } })

Mongoose request for id field returns id and _id

In my Mongoose schema I have an id field which has a unique ID for each document. This runs off the same system used by the default _id field like so:
var JobSchema = new mongoose.Schema({
id: { type:String, required:true, unique:true, index:true, default:mongoose.Types.ObjectId },
title: { type: String },
brief: { type: String }
});
module.exports = mongoose.model("Job", JobSchema);
Now, if I query the schema to get id and title I'd do it like this:
Job.find().select("id title").exec(function(err, jobs) {
if (err) throw err;
res.send(jobs);
});
However, I've found this returns id and title as expected, but it also return the default _id field. Why is that and how do I stop it?
Inside the find() function you can pass two parameters (criteria and projection). Projection are the fields that you want (or not). In your case you can change your code to
Job.find({}, {_id:0, id: 1, title: 1}, function(err, jobs) {
if (err) throw err;
res.send(jobs);
});
and it should do it.
There is an option to prevent the id on schema level.
For me this worked perfectly fine.
new Schema({ name: String }, { id: false });
Mongoose Docs

Categories