Here is my Follow model
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let FollowSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
followers: [{
type: Schema.Types.ObjectId,
ref: 'Card'
}],
following: [{
type: Schema.Types.ObjectId,
ref: 'Card'
}]
});
module.exports = mongoose.model('Follow', FollowSchema);
Here's my Card model
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let CardSchema = new Schema({
title: String,
content: String,
likes: Number,
createdById: {
type: Schema.Types.ObjectId,
ref: 'User'
}
});
module.exports = mongoose.model('Card', CardSchema);
A typical Follow Model in DB will have something like this:
{
"_id" : ObjectId("59f0eef155ee5a5897e1a66d"),
"user" : ObjectId("59e3e617149f0a3f1281e849"),
"following" : [
ObjectId("59e21942ca5652efc4ca30ab"),
ObjectId("59e13b2dca5652efc4ca2cf5")
]
}
Here's what I'm trying to do:
To get all post from those you follow, find user in Follow model, and for each ObjectId in the following array, pull all documents from Card model, matching createdById field.
Using Mongoose Populate Virtuals, how do I do the schema relationship and populate query eventually?
Or, how would I go about creating and querying such a relationship with or without virtuals?
Related
I am using mongoose and have two schemas, user and community:
UserSchema:
const UserSchema = new Schema({
name: String,
communities: [{ type: Schema.Types.ObjectId, ref: CommunityModel }],
}, { timestamps: true });
}
Community:
const CommunitySchema = new Schema({
name: String,
users: [
{ type: Schema.Types.ObjectId, ref: "User" }
]
}, { timestamps: true });
When user joins a community, I want to know when it happened, so I'd like to add a joinedAt or createdAt to each community in the UserSchema. How could I achieve it if it is a reference? Is it possible? And if not, what could be the alternative?
Thanks!
This is the correct answer:
AI solved it for me, here is the correct example:
import * as mongoose from 'mongoose';
const Schema = mongoose.Schema;
interface User {
name: string;
email: string;
communities: Community[];
}
interface Community {
name: string;
description: string;
users: User[];
}
const userSchema = new Schema({
name: String,
email: String,
}, {
timestamps: true,
});
const communitySchema = new Schema({
name: String,
description: String,
}, {
timestamps: true,
});
// Define the user_communities table using the communitySchema
const userCommunitySchema = new Schema({
user: { type: Schema.Types.ObjectId, ref: 'User' },
community: { type: Schema.Types.ObjectId, ref: 'Community' },
joined_on: Date,
}, {
timestamps: true,
});
// Use the userCommunitySchema to create the UserCommunity model
const UserCommunity = mongoose.model('UserCommunity', userCommunitySchema);
// Use the userSchema to create the User model, and define a virtual property
// for accessing the user's communities
userSchema.virtual('communities', {
ref: 'Community',
localField: '_id',
foreignField: 'user',
justOne: false,
});
const User = mongoose.model<User>('User', userSchema);
// Use the communitySchema to create the Community model, and define a virtual property
// for accessing the community's users
communitySchema.virtual('users', {
ref: 'User',
localField: '_id',
foreignField: 'community',
justOne: false,
});
const Community = mongoose.model<Community>('Community', communitySchema);
The userSchema and communitySchema are then used to create the User and Community models, respectively. For the User model, a virtual property called communities is defined using the virtual method. This virtual property is used to specify how to populate the user.communities property when querying the database. The communitySchema also defines a users virtual property, which is used to populate the community.users property when querying.
this is what I have and it works:
var comboSchema = new Schema({
components: [{
type: Schema.Types.ObjectId,
ref: "Component"
}]
})
This is what I want to achieve:
var comboSchema = new Schema({
components: [{
type: Schema.Types.ObjectId,
ref: "Component",
amount: {type: Integer}
}]
})
Is it possible in MongoDB, if not what is the best workaround?
Thank you :-)
This schema work because of an element or filed name is provided
var comboSchema = new Schema({
components: [{
type: Schema.Types.ObjectId,
ref: "Component"
}]
})
Now you made a single mistak you want to create schema name without name in object with two different filed
Right way to create schema like this is to make other variable inside of array which contain type of filed
var comboSchema = new Schema({
components: [{
id: {
type: Schema.Types.ObjectId,
ref: "Component"
},
amount: { //If you want to make every component amount
type: Number
}
}]
})
Or
var comboSchema = new Schema({
amount: { type: Number },
//If you want to make only single amount on multiple components
components: [{
componentId: {
type: Schema.Types.ObjectId,
ref: "Component"
}
}]
})
But in both case you can't populate directly. You need to use aggregation for that to get data for embedded documents.
This is a MERN app, hosted on github, and it works perfectly on localhost. Unfortunately, it does not work on Heroku.
The issue is the API request, it must return an object and populate an array of OIDs (see Department Model). API request is working. I'm getting the data from MLab, but it doesn't populate... instead returns: "surveys":[]
API File
router.get('/department_data/:d_oid', function(req, res) {
Department.findOne({_id: req.params.d_oid}).populate("surveys").exec(function(err,doc){
if(err) throw(err)
res.send(doc)
})
});
Department Model
**Department Model**
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
// Create the survey schema
var departmentSchema = new Schema({
department_name: {
type: String,
trim: true,
required: true
},
surveys: [{
type: Schema.Types.ObjectId,
ref: 'Surveys'
}],
participants: [{
type: String
}],
create_date: {
type: Date,
default: Date.now
},
created_by: {
type: Schema.Types.ObjectId,
ref: 'Created_By'
},
});
departmentSchema.index({ department_name: 1, created_by: 1}, {unique: true});
const Department = mongoose.model('Departments', departmentSchema);
module.exports = Department;
Survey Model
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
// Create the survey schema
var surveySchema = new Schema({
survey_name: {
type: String,
trim: true,
required: true
},
questions: [{
type: Schema.Types.ObjectId,
ref: 'Questions'
}],
created_date: {
type: Date,
default: Date.now
}
});
const Survey = mongoose.model('Surveys', surveySchema);
module.exports = Survey;
Solved.
The problem was in the database: the ref OIDs got scrambled with a previous update, so when it was trying to populate, Mongoose couldn't find any matching OIDs.
Solution: we had to purge and re-seed. When the correct OID references exist, this code works as expected in localhost & Heroku.
my case is:
I have postSchema and commentSchema, like this:
const postSchema = new Schema({
comments: [
{
type: Schema.Types.ObjectId,
ref: 'Comment'
}
]
}
const commentSchema = new Schema({
post: {
type: Schema.Types.ObjectId,
ref: 'Post'
}
}
If I know the post._id, I want to query the post documents and comment documents.
I think there are two way:
popluate: Post.findById(post._id).populate('Comment').exec()
start another query:
Post.findById(post._id).exec()
Comment.find({post: new Types.ObjectId(post._id)}).exec()
So, which is better? Or, when to use populate and when to start another query?
I am creating simple RestApi using MongoDB, Mongoose, Node.js, Express.js and In which there will be multiple users and many more users can sign up and there will be an entry for each user in user collection(database). And my user Schema(users.js) will be like
var mongoSchema = mongoose.Schema;
var userSchema ={
mobileno: {
type:String
},
firstname: {
type:String
},
lastname: {
type:String
},
facebookid: {
type:String
},
userimage: {
type:String
}
}
module.exports = mongoose.model('user', userSchema);
Now each user can save one or more products as follows
Now which one would be the best solution:
Should I use separate collection (products collection with one field
like mobile no for reference)
Or Should I use subdocument or nested objects
My personal choice is second one but I am new in MongoDB and Mongoose environment. Please help me what I need to change in users schema.
You can do it like this :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema{
mobileno: {
type:String
},
firstname: {
type:String
},
lastname: {
type:String
},
facebookid: {
type:String
},
userimage: {
type:String
}
}
var productSchema = new Schema{
_user:{type: Schema.ObjectId, ref: 'user'}
prod_name: {
type:String
},
prod_cost: {
type:String
}
}
module.exports = mongoose.model('user', userSchema);
module.exports = mongoose.model('products', productSchema);
You can reference user to product table (i,.e, just like joins in mysql)
And populate while fetching the profile :
Models.products.find(criteria, projection, options).populate([
{path: '_user', select: 'prod_name, prod_cost'},
]).exec(callback);
Thanks & Regards
The second choice is generally preferred. The schema for the product key would look like -
products: [productname: String, productdesc: String, ]
However, in some cases the first option to create a separate product collection makes more sense. This would happen if the collection depends on some external source and is fairly dynamic in nature. Here you would find it easier to update at one place rather than a lot of places. In this case, you can have a schema like
products: [productSchema]
Here for getting the product details, you would need to do $lookup operations
I think, the better way is other way around.
Save the product as a collection and user as another collection.
In product collection, save the reference of user.
Then use populate() to populate user in product, if you want.
After reading existing stack overflows answers I think following approach would be right. Please suggest or correct me if I am wrong.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var productSchema = new Schema{
prod_name: {
type:String
},
prod_cost: {
type:String
}
}
var userSchema = new Schema{
mobileno: {
type:String
},
firstname: {
type:String
},
lastname: {
type:String
},
facebookid: {
type:String
},
userimage: {
type:String
},
products: [productSchema]
}
module.exports = mongoose.model('user', userSchema);
module.exports = mongoose.model('products', productSchema);