Populate mongoose across levels and display certain fields - node.js

const userSchema = new Schema({
name: String,
email: String,
friends: [{ type: ObjectId, ref: 'User' }]
});
User.
findOne({ name: 'Val' }).
populate({
path: 'friends',
populate: { path: 'friends' }
});
The above schema populates the entire User fields for friends array, but for the friends array, I need only name to be populated. How do I limit the fields in the nested level in mongoose.

Generally speaking, you would first populate friends as you have done and then add select to simply get the fields that you wanted to extract from the User model.
User.findOne({ name: 'Val' })
.populate({
path: 'friends',
select: ['name', 'fieldName']
})
I have added array of elements to demonstrate that you can select more fields that way, in your case it would just be name.

Related

Mongoose populate by field not _id

I have these two schema
const User = new mongoose.Schema({
username: {
type: String,
unique: true,
}
})
const Product = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}
//...Other product information
})
and when I query product I can populate the product user like this
await database.Product.findOne({}).populate("user")
this will populate the user by his id but I want to populate the user by his username since it never gonna repeat and it's unique. I there is a way to reference a model by another field other than the _id
Do this:
await database.Product.findOne({}).populate('user',{path: 'username'})

How to query documents of one model, from referenced field from another model?

How I could query with mongoose all food by City _id which is referenced in Place model, and Place model referenced in Food model.
EDIT: (example) If I select New York (City), I want to get all food from New York.
const FoodSchema = new Schema({
place: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Place',
required: true
}})
const PlaceSchema = new Schema({
city: {
type: mongoose.Schema.Types.ObjectId,
ref: 'City',
required: true
}})
const CitySchema = new Schema({
name: {
type: String}})
You can use populate() multiple times. This code from the official documentation gives an example where they query a user, populates its friends, and then the friends of the friends:
User.
findOne({ name: 'Val' }).
populate({
path: 'friends',
// Get friends of friends - populate the 'friends' array for every friend
populate: { path: 'friends' }
});
In your case this would be
Food.find().populate({path: 'place', populate: {path: 'city'}})

Match specific value in mongoose populate

Following is the schema of a user collection:
const Mongoose = require('mongoose')
const Schema = Mongoose.Schema
const userSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String
},
supporterOf: [{
type: Schema.Types.ObjectId,
ref: 'individual',
required: false
}],
})
module.exports = Mongoose.model('user', userSchema);
I want to populate 'supporterOf' which is a collection of individual (ref: individual).
The 'supporterOf' contains an array of ObjectId.
I am having the problem of matching the specific objectId with that ObjectId array.
Can anyone suggest me how I can match specific ObjectId with an array of ObjectIds in populate function?
You have a reference of 'individual' in supporterOf and you want to populate only relevant object from the array of individuals?
If this is right case then do the following:
YourUserModel.findById(userId, function (err, user) {
console.log(user)
}).populate({
path: 'supporterOf',
match: {
yourObjectOfIndividualDocument: yourMatchingIdOfIndividual
}
})
.exec()
Replace yourObjectOfIndividualDocument: yourMatchingIdOfIndividual by name: 'abcd'.
Here name is the field of Individual document not of User document.
You add condition in populate
if you wanted to populate fans array based on their age, and return, at most, any 5 of them
.populate('fans', null, { age: { $gte: 21 }}, { limit: 5 })

How to display all the posts referenced to logged in user?

I am trying to understand Mongoose's populate function and am so far stumped by available resources and the docs.
Essentially I have a schema arrangement as below, and I am trying to display all the posts referenced to a user on one page rendered with ejs.
var UserSchema = new Schema ({
username: String,
password: String,
posts: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Post"
}
]
});
var PostSchema = new Schema ({
Title: String,
Content: String,
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
}
});
I have got passport/sessions setup, so I am able to get the id of the active user. Using this id I would like to display all of the user's posts. I have been stuck on this for hours and tried following various tutorials and different approaches, please someone put me out of my misery! How should I approach this?
Try to match the users first with the ids list (activeUserIds) then populate the posts and author fields in fetched records.
await User.find({'_id': {$in: [activeUserIds]}})
.populate({
path: 'posts',
model: 'Post',
populate: ({
path: 'author',
model: 'User'
})
});

How to populate a document inside an array inside another document?

Sorry if title looks complicated... I couldn't think of a better way to describing it.
My real case situation matches the following Schemes:
Collection1:
const mongoose = require('mongoose');
const itemSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: [true, 'Name is required.'] },
quantity: { type: Number, required: [true, 'Quantity is required.'] },
collection2: { type: mongoose.Schema.Types.ObjectId, ref: 'Collection2' }
}, { _id : false });
const collection1Schema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: [true, 'Name is required.'] },
imagePath: { type: String, required: [true, 'Image is required.'] },
items: [itemSchema]
});
module.exports = mongoose.model('Collection1', collection1Schema);
Note: itemsSchema is inside the collection1 file (and having no declared _id's) because they only exist for the Collection1 model (considering "quantity" and other fields I removed for simplification). This itemsScheme is not needed elsewhere as another collection.
Collection2:
const mongoose = require('mongoose');
const collection2Schema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: [true, 'Name is required.'], unique: true }
});
module.exports = mongoose.model('Collection2', collection2Schema );
Note: Other properties (such as 'imagePath') were removed for simplification.
Now, this is the query I am trying to run:
Collection1.find()
.populate({
path: 'items',
populate: {
path: 'collection2', model: 'Collection2'
}
})
.then(...)
.catch(...);
And this is the error message I am getting when I run it:
Error fetching collection1: Cast to ObjectId failed for value "{
name: 'an item name',
quantity: 750
}" at path "_id" for model "Collection1"
The exact same error happens if I just run:
Collection1.find()
.populate('items')
.then(...)
.catch(...);
Maybe I cannot run .populate('items') because it has no declared model. If this is the case, how can I populate collection2 while querying collection1? Again, I cannot consider storing items in a separated collection.
But if I run:
Collection1.find()
.populate('collection2')
.then(...)
.catch(...);
I get the items, no errors, but it doesn't populate collection2. Well, it makes sense for the items because they're just an array of a block of properties inside collection1. But what about populating collection2?
Collection2 already has a few documents added, all with their _ids and other fields well filled. In the controller, I set _id: new mongoose.Types.ObjectId(), while creating a new document for both cases, Collection1 and Collection2.
In the front-end, I create a new document for Collection1, I add items, each item with a document from Collection2, and I save everything with no errors. I also confirmed everything is been properly saved (collection1 has list of items and each item an _id reference to collection2). The only problem is populating collection2 inside this array.
I have already tried restructuring everything with _ids (including itemScheme) and dropping all collections to test it again but no success.
I have been stuck with this problem for about three days now.
Is there any special property I should be setting for populate to make it work for this specific structure?
Thanks in advance...
populate('items')
This will not work as item is not a model.
What you want is following:
Collection1.find()
.populate('items.collection2')
.then(...)
.catch(...);
This will populate collection2 in all the array elements

Resources