I've got two models in mongoose:
const user = mongoose.Schema({
name: String,
...
});
and
const moderator = mongoose.Schema({
name: String,
...
});
When I access these collections with:
user.find()
I get in response list of users and moderators separetly.
What I want to achive is to join these two list together to get a list based on this model:
const myDataSchema = mongoose.Schema({
user: {type: Schema.Types.ObjectId, ref: 'user'},
moderator: {type: Schema.Types.ObjectId, ref: 'moderator'}
});
Where one of attributes (either user or moderator) will be set.
I solved my problem. Instead of using the mongoose schema I created my "own object". My code:
let list= [];
users.forEach( function (user)
{
list.push({user: user});
});
moderators.forEach( function (moderator)
{
list.push({moderator: moderator});
});
It's probaly not the most efficient way but it works.
Related
I want to populate all items inside an array from the collection I reference.
It never works and poplute doesnt seem to run unless I populate and then use .populated on the result. I dont understand what this is?
const userSchema = new mongoose.Schema({
email: String,
following: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Product'
}]
});
const productSchema = new mongoose.Schema({
name: String,
price: String
...
});
const products = await User.findOne({ _id: req.user._id }).populate('following')
const productsAgainPopulated = products.populated('following');
only productsAgainPopulated will actually return the followed products.
products will only return me the user
so I'm been making a site that has comments section, messaging, profile and shopping for the user. I been wondering about when making a schema for those functions, is it better to have all in one schema like
userSchema {
name: String,
....
....
}
or have them seperate like
userSchema {
}
commentSchema {
}
gallerySchema {
}
No one can give you clear answer for this, everyone has different views.
Basically, It depends on your project's scalability
As I see your requirement for this project
You can create a single schema and use it as embedded form, but it's not a very good idea if you are scaling the app.
My recommendation is to create the separate schema for all the tasks which will be easy to debug,scaling the app and in readable form.
Edit
If you are creating separate schema and want to connect them then you can use populate on the basis of ObjectId
See the docs to populate collections
Example
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
Population
Story
.findOne({ title: 'Once upon a timex.' })
.populate('_creator')
.exec(function (err, story) {
if (err) return handleError(err);
console.log('The creator is %s', story._creator.name);
// prints "The creator is Aaron"
});
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!
I have two MongoDB collections - comments
var mongoose = require('mongoose');
var CommentSchema = new mongoose.Schema({
body: String,
author: String,
upvotes: {type: Number, default: 0},
post: { type: mongoose.Schema.Types.ObjectId, ref: 'Profile' }
});
mongoose.model('Comment', CommentSchema);
and users
var mongoose = require('mongoose');
var UserSchema = new mongoose.Schema({
userName: String,
userJobRole: String,
userEmail: String,
userPhone: String,
userTimeZone: String,
post: { type: mongoose.Schema.Types.ObjectId, ref: 'Profile' }
});
mongoose.model('User', UserSchema);
I want to use populate for each of these schemas in my get request. One for users and one for comments from these models.
router.get('/profiles/:profile', function(req, res, next) {
req.post.populate('users', function(err, post) {
if(err) { return next(err) }
res.json(post);
});
});
I can only figure out how to call one.
Does Mongoose allow you to populate from two schemas?
In order to populate multiple paths, you can pass a space delimited string of path names to the populate method on any document as follows:
Story
.find(...)
.populate('fans _creator') // space delimited path names
.exec()
This is taken directly from the Mongoose docs http://mongoosejs.com/docs/populate.html
I'm trying to make a many-to-many relation between two documents in mongoose. Just can't make it work.
I've been trying to utilize the mongoose populate method, but with no success. Does anyone know any good tutorials or example on how to take on the matter?
Update:
Got schemas
var EventSchema = new Schema({
users: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
});
and
var UserSchema = new Schema({
events: [{
type: Schema.Types.ObjectId,
ref: 'Event'
}]
});
In my tests I pused to event model user like so
event.users.push(user);
event.save(function(err, doc) {
user.events[0].should.equal(event._id);
done();
});
firstly I need to push somehow saved event to added user to event. Then by using populate I should can 'dress up' every object in events array and users array. Preferably in post save callback, if I understood populate correctly.
This test pases
it('creates', function(done) {
event.users.append(user);
event.save(function(err, ev) {
user.save(function(err, doc) {
doc.events[0].should.equal(ev._id);
doc.populate('events', function(err, d) {
console.log(d);
done();
});
});
});
});
So I know the ids are stored correctly, but when I run doc.populate() the returned document has events array empty. Just don't get it.
Made it work... used mongo-relation package to add the needed ids for me, but docs for this plugin made me change the schema form
var UserSchema = new Schema({
events: [{
type: Schema.ObjectId,
ref: 'Event'
}]
});
to
var UserSchema = new Schema({
events: [Schema.ObjectId]
});
once corrected, it worked.