I am trying to make some nested population. User model is populated the way i expect it to be.
But i am having trouble with nested population of a Post model. It's not populated at all.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
mongoose.connect(`mongodb://localhost:27017/testDB`);
var UserSchema = new Schema({
name:String,
post: {
type: Schema.Types.ObjectId,
ref: 'Post'
}
});
var PostSchema = new Schema({
title:String,
subscriber:{
type:Schema.Types.ObjectId,
ref:'Subscriber'
}
});
var SubscriberSchema = new Schema({
name:String
});
var User = mongoose.model("User", UserSchema);
var Post = mongoose.model('Post',PostSchema);
var Subscriber = mongoose.model('Subscriber',SubscriberSchema);
User
.find()
.populate([{
path:'post',
model:'Post',
populate:{
model:'Subscriber',
path:'subscriber'
}
}])
.exec()
.then(function(data){
console.log(data);
mongoose.disconnect();
});
You are calling .populate incorrectly.
Please try this:
User
.find()
.populate('post')
.populate({
path: 'post',
populate: {
path: 'subscriber',
model: 'Subscriber'
}
})
.exec()
.then(function (data) {
console.log(data);
mongoose.disconnect();
});
For more info check this out.
Related
This issue seems to be common but the answers for it vary. I am trying to populate these two models with their data.
const express = require('express');
const mongoose = require('mongoose');
const app = express();
app.listen(4000,()=>{
console.log('server listening on port 4000')
});
mongoose.connect('mongodb://localhost:27017/testDB',{useNewUrlParser:true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify:true });
const UserSchema = new mongoose.Schema({
username: String,
})
const PostSchema = new mongoose.Schema({
content: String,
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
}
})
const Post = mongoose.model('Post', PostSchema);
const User = mongoose.model('User', UserSchema);
const user = new User({
username: 'alex antoine',
})
const posts = new Post({
content: 'I hope this works'
})
UserSchema.virtual('Post',{
localField: '_id',
foreignField: 'author',
ref:'Post',
})
const populateUser = async(username)=>{
const user = await User.findOne({username}).populate('posts');
const userPopulated = await user.populate('Post').execPopulate();
console.log(userPopulated);
}
const save = async()=>{
user.save();
posts.save();
}
save();
populateUser('alex antoine');
The response I received from this is
Populated User {
posts: [],
_id: 60dbe989fd1ab074d0ab0541,
username: 'alex antoine',
__v: 0
}
This seems to be a common issue that a lot of people had but none of their answers seems to work for me. Thanks in advance.
You're not declaring your user's posts as a virtual field right. Your PostSchema is correct, but your UserSchema should look like this:
const UserSchema = new mongoose.Schema({
username: String
})
UserSchema.virtual('posts', {
ref: Posts,
localfield: '_id',
foreignField: 'author'
});
This way, when dealing with a user document, you can populate its posts:
user.populate('posts').execPopulate();
result User.findOne({username}).populate('posts').exec();
// At the exec() try using execPopulate()
Then at the ref add the required: true` option
The following are two blocks of code, the first one is my Schema and the second one is my query. The Payment model is getting saved and it has the id referring to the user. Can I know where I am going wrong, is there any thing wrong with the fundamental ?
Here is my schema of User and Payment
User:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
var paymentSchema = new Schema({
amount: Number,
user: {
type: Schema.Types.ObjectId,
ref: 'User'
}
});
var userSchema = new Schema({
email: String,
payment: {
type: Schema.Types.ObjectId,
ref: 'Payment'
}
});
module.exports = mongoose.model('User', userSchema);
module.exports = mongoose.model('Payment', paymentSchema);
Here is my query which I am using to populate using promise:
User.findOne({email: req.query.email})
.populate('payment')
.select('_id payment')
.then(function(user) {
res.json(user);
});
I'm trying to populate post with comments. With populating author I didn't have any problems. I tried to populate just comments without author and it didn't work..
Here is the comment model:
const mongoose = require('mongoose');
const schema = mongoose.Schema;
const User = require('./user');
commentSchema = new schema({
comment: String,
author: { type: schema.Types.ObjectId, ref: 'User' },
})
const Comment = module.exports = mongoose.model('Comment', commentSchema);
Here is the route:
router.get('/posts/:id', (req, res) => {
Post.findById({ _id: req.params.id })
.populate('author')
.populate('comments')
.exec((err, post) => {
if (err) {
console.log(err);
} else {
res.json(post);
}
});
});
can you explain me how to organize mongoose models to create one to many connections? It is needed keep separate collections.
suppose i have stores and items
//store.js
var mongoose = require('mongoose');
module.exports = mongoose.model('Store', {
name : String,
itemsinstore: [ String]
});
//item.js
var mongoose = require('mongoose');
module.exports = mongoose.model('Item', {
name : String,
storeforitem: [String]
});
Am i doing it in the right way?
And how to access pass data to arryas?
Here is the code yo enter name to item. But how to enter id to array of id's (itemsinstore)?
app.post('/api/stores', function(req, res) {
Store.create({
name: req.body.name,
}, function(err, store) {
if (err)
res.send(err);
});
})
You should use model reference and populate() method:
http://mongoosejs.com/docs/populate.html
Define your models:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var storeSchema = Schema({
name : String,
itemsInStore: [{ type: Schema.Types.ObjectId, ref: 'Item' }]
});
var Store = mongoose.model('Store', storeSchema);
var itemSchema = Schema({
name : String,
storeForItem: [{ type: Schema.Types.ObjectId, ref: 'Store' }]
});
var Item = mongoose.model('Item', itemSchema);
Save a new item into an existing store:
var item = new Item({name: 'Foo'});
item.save(function(err) {
store.itemsInStore.push(item);
store.save(function(err) {
// todo
});
});
Get items from a store
Store
.find({}) // all
.populate('itemsInStore')
.exec(function (err, stores) {
if (err) return handleError(err);
// Stores with items
});
You can do using the best practices with Virtuals.
Store.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const StoreSchema = new Schema({
name: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})
StoreSchema.virtual('items', {
ref: 'Item',
localField: '_id',
foreignField: 'storeId',
justOne: false // set true for one-to-one relationship
})
module.exports = mongoose.model('Store', StoreSchema)
Item.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const ItemSchema = new Schema({
storeId: {
type: Schema.Types.ObjectId,
required: true
},
name: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Item', ItemSchema)
StoreController.js
const Store = require('Store.js')
module.exports.getStore = (req, res) => {
const query = Store.findById(req.params.id).populate('items')
query.exec((err, store) => {
return res.status(200).json({ store, items: store.items })
})
}
Keep in mind that virtuals are not included in toJSON() output by default. If you want populate virtuals to show up when using functions that rely on JSON.stringify(), like Express' res.json() function, set the virtuals: true option on your schema's toJSON options.
// Set `virtuals: true` so `res.json()` works
const StoreSchema = new Schema({
name: String
}, { toJSON: { virtuals: true } });
Okay, this is how you define a dependancy:
var mongoose = require('mongoose');
module.exports = mongoose.model('Todo', {
name : String,
itemsinstore: [{ type: Schema.Types.ObjectId, ref: 'Item' }]
});
And make sure you have different names:
var mongoose = require('mongoose');
module.exports = mongoose.model('Item', {
name : String,
storeforitem: [String]
});
Keep an eye on Item in both cases.
And then you just want to pass the array of ObjectIDs in it. See more here: http://mongoosejs.com/docs/populate.html
Try this:
Store.findOne({_id:'5892b603986f7a419c1add07'})
.exec (function(err, store){
if(err) return res.send(err);
var item = new Item({name: 'Foo'});
item.save(function(err) {
store.itemsInStore.push(item);
store.save(function(err) {
// todo
});
});
I'm trying populate an array with entire information of another collection and I can't get it.
I have 2 collections: users and exams and I want to show a json response containing user information and exams buyed by the user.
My problem is that I don't know how to populate examsPurchased with entired exams information (name,numberOfQuestions,yearOfExam...)
¿How can I do that?
This is my final result
And this is my code
// USER MODEL
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// Schemas
var userSchema = new Schema({
name : String,
hobbies: {
name : String,
ubicacion:String
},
examsPurchased : [new Schema({
exams: {type: Schema.ObjectId, ref: 'exams'}
})]
});
module.exports = mongoose.model('users', userSchema);
// EXAM MODEL
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// Schemas
var examSchema = new Schema({
year : Number,
count : Number
});
module.exports = mongoose.model('exams', examSchema);
// ROUTES
router.route('/user/:user_id').get(function(req,res){
user
.findById(req.params.user_id)
.populate('examsPurchased._id')
.exec(function (err, completeUser) {
if(err) {
console.log(err);
}
res.send(completeUser);
});
});
The problem is that you aren't populating the good field:
// ROUTES
router.route('/user/:user_id').get(function(req,res){
user
.findById(req.params.user_id)
.populate('examsPurchased.exams', 'year count') // Line changed
.exec(function (err, completeUser) {
if(err) {
console.log(err);
}
res.send(completeUser);
});
});