I'm new to NoSQL, in this case is MongoDB. I'm trying to make an API using ExpressJS and Mongoose. that have some data models
User.js
const UserSchema = new mongoose.Schema(
{
username: {
type: String,
required: true,
min: 3,
max: 50,
unique: true,
},
email: {
type: String,
required: true,
max: 50,
unique: true,
},
password: {
type: String,
required: true,
min: 6,
},
profilePicture: {
type: Schema.Types.ObjectId,
ref: "Image",
},
}
Image.js
const ImageSchema = new mongoose.Schema(
{
desc: {
type: String,
},
url: {
type: String,
},
},
{ timestamps: true }
)
Post.js
const PostSchema = new mongoose.Schema(
{
username: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
desc: {
type: String,
max: 300,
required: true,
},
images: [
{
type: Schema.Types.ObjectId,
ref: "Image",
},
],
comments: [
{
type: Schema.Types.ObjectId,
ref: "Comment",
},
],
}
)
Comment.js
const CommentSchema = new mongoose.Schema(
{
user: {
type: Schema.Types.ObjectId,
ref: "User",
},
text: {
type: String,
required: true,
trim: true,
},
}
Now I want to perform a query that gets all comments based on specific postId. And the response data must include User data and image url that related to User. I tried this to get comment data
const comments = await Comment.find({post: req.params.postId}).populate("user")
It returned Comment with User data, but not include Image. How do I perform that query?
Try this (using the pupulate method with object configuration):
const comments = await Comment.find({post: req.params.postId}).populate({
path: 'user',
populate: {
path: 'profilePicture'
}
})
Here you can also select particular fields of each schema for example.
Let me know if it works for you.
Reference
Related
I have two collections in MongoDB database, Post and User. Each post contains the creator's ObjectId. When fetching all posts from the database, I want to add the name information, which is a field of User/creator. I tried to access the name field by post.creator.name, but it is not working.
const postSchema = new Schema(
{
title: {
type: String,
required: true,
},
category: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
imageUrl: {
type: String,
required: true,
},
creator: {
type: Schema.Types.ObjectId,
ref: "User",
required: true,
},
},
{ timestamps: true }
);
const userSchema = new Schema({
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
status: {
type: String,
required: true,
},
isExpert: {
type: Boolean,
required: true,
},
posts: [
{
type: Schema.Types.ObjectId,
ref: "Post",
},
],
});
exports.getPosts = (req, res, next) => {
Post.find({}).then((posts) => {
const postsWithAuthorName = posts.map(post => {
return {
...post,
name: post.creator.name
}
})
res.status(200).json({
posts: postsWithAuthorName,
});
});
};
Try this
Post.find({}).populate('creator', 'name')
See populate doc for reference.
When you query posts, creator is just an ObjectId, so you can't just call .name on it. To make it work you need to lookup this data by using e.g. populate.
I have 2 schemas User and Restaurant, and user has an array of restaurants, am trying to reach when deleting the restaurant delete its reference from user automatically, am trying to reach it with the model.pre('remove')..but when I delete a restaurant the reference id it still exist in User.
Here is my User Schema:
const userSchema = new Schema(
{
email: {
type: String,
trim: true,
// required: true,
unique: true,
},
password: {
type: String,
// required: true,
min: 5,
},
stripeCustomerId: {
type: String,
// unique: true,
},
linkedAffiliateUser: {
type: String, //mongoose.Schema.Types.ObjectId,
},
restaurants: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Restaurant",
},
],
role: {
roleId: { type: Number, minlength: 1, maxlength: 1, required: true },
roleName: { type: String, trim: true, required: true },
},
// seperated schema
},
{ timestamps: true }
);
export default mongoose.model("User", userSchema);
and here is my Restaurant Schema:
const restaurantSchema = new Schema({
restaurantOwner: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
Name: {
type: String,
trim: true,
},
server: { type: mongoose.Schema.Types.ObjectId, ref: "ServerUser" },
restaurantLinkAccess: {
type: String,
required: true,
trim: true,
unique: true,
},
});
restaurantSchema.pre("remove", function (next) {
this.model("User")
.update(
{ restaurantSchema: this },
{ $pull: { comments: this._id } },
{ multi: true }
)
.exec(next);
});
export default mongoose.model("Restaurant", restaurantSchema);
I also tried to solve it like this:
restaurantSchema.pre("remove", function (next) {
this.model("User").remove({ $pull: { restaurants: this._id } }, next);
});
Please help.
so i'm trying ref a array of daysOff (Ferias model) as a fiel in a User model,
i'm new to MongoDB and mongoose, and i'm trying to build a API that manages a company workers days off.
I apologyse in advance for the "format" of this question but it's the very first time that I post a question in StackOverflow :)
Thanks u all!
const mongoose = require("mongoose");
const moment = require("moment");
const feriasSchema = mongoose.Schema(
{
user: {
type: mongoose.Types.ObjectId,
required: true,
ref: "User",
},
firstName: {
type: String,
ref: "User",
},
lastName: {
type: String,
ref: "User",
},
workerNumber: {
type: Number,
ref: "User",
},
sectionOfWork: {
type: String,
ref: "User",
},
totalFerias: {
type: Number,
required: true,
},
//this is the field i want to add in User model as an array of (dates format DD/MM/YYYY)
ferias: {
type: [String],
//default: [Date],
required: true,
},
tipoFerias: {
type: String,
required: true,
},
modo: {
type: String,
required: true,
},
},
{ timestamps: true }
);
module.exports = mongoose.model("Ferias", feriasSchema);
// USER MODEL
const userSchema = mongoose.Schema(
{
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
email: {
type: String,
required: [true, "Please enter a valid email address"],
unique: true,
},
password: {
type: String,
required: [true, "Please enter a password"],
},
workerNumber: {
type: Number,
required: true,
unique: true,
},
sectionOfWork: {
type: String,
required: true,
},
chefia: {
type: String,
required: true,
},
//this is the field i want to be an array (from Ferias model)
ferias: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Ferias",
}],
role: {
type: String,
required: true,
},
},
{ timestamps: true }
);
module.exports = mongoose.model("User", userSchema);
what am i doing wrong?
i'm getting and empty array ...
in express I can send the questioned data separately but u want to send a json to some frontend with all the fields of a user, with the "ferias" array present.
I just started learning express and mongodb. I recently faced the kind of problem, I'm trying to select all the subdocuments which are inside of Room model.
const books = await Room.find().populate('book');
But it returns whole room document when i want to select only bookings field.
Here's the book schema
const bookSchema = new mongoose.Schema({
startDate: {
type: Date,
required: true,
},
endDate: {
type: Date,
required: true,
},
name: {
type: String,
required: true,
},
phone: {
type: String,
required: true,
},
});
module.exports = mongoose.model("book", bookSchema)
And here's the room schema
const roomSchema = new mongoose.Schema({
currentlyReserved: {
type: Boolean,
default: false,
},
people: {
type: Number,
required: true,
},
roomNumber: {
type: Number,
required: true,
},
pricePerPerson: {
type: Number,
required: true,
},
reservedUntil: {
type: Date,
default: null,
},
reservedBy: {
type: String,
default: null,
},
bookings: {
type: [{ type: mongoose.Schema.Types.ObjectId, ref: "book" }],
},
});
module.exports = mongoose.model("room", roomSchema);
You can project with with second arg to find().
https://docs.mongodb.com/manual/reference/method/db.collection.find/#projection
const books = await Room.find({}, {bookings: 1}).populate('bookings');
I'm looking to make a populate() on a find() request but specifying multiple models, so if no occurrence is found on the first specified model the population will make on the second.
Here is an example of what I would like to do :
const userSch = new Schema({
username: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
mail: {
type: String,
required: true,
unique: true,
}
});
const botSch = new Schema({
username: {
type: String,
required: true,
},
token: {
type: String,
required: true,
unique: true,
},
owner: mongoose.Schema.Types.ObjectId
});
const nspSch = new Schema({
name: String,
channels: [channels],
users: [{
id: {
type: mongoose.Schema.Types.ObjectId,
},
bot: {
type: Boolean,
}
}],
});
const channels = new Schema({
name: String,
message: [{
user: {
type: Schema.Types.ObjectId,
},
content: String,
}],
});
const nsp = mongoose.model('namespace', nspSch);
const Auth = mongoose.model('users', userSch);
const BotAuth = mongoose.model('bots', botSch);
function returnMs(nspID, channelID, callback) {
nsp.findOne({'_id': nspID}).populate({
path: 'channels.message.user',
model: 'users' || 'bots',
select: '_id username',
})
.exec(function(err, r) {
...
})
}
If there is ever an npm package, or a solution or even a track to code it, please share it.
Thank you