Mongoose query from two schemas that share same reference - node.js

Suppose I have two schemas:
1. UserEnrolledCourses
var userCoursesSchema = new mongoose.Schema({
user: { type: mongoose.Schema.Types.ObjectId, ref: 'users'},
courseId: { type: mongoose.Schema.Types.ObjectId, ref: 'courses'},
isEnrolled: Boolean,
});
2. CourseResources
var resourcesSchema = new mongoose.Schema({
courseId: { type: mongoose.Schema.Types.ObjectId, ref: 'courses', required: true },
type: {type:String, required:true},
});
Both of them shared the same courseId reference from courses schema.
So, my aim is to generate result from query that for each courseId that one user enrolled, list all of the resources that available. Is that possible?

In mongoDB, you are performing queries on one concrete collection. The only exception is the left outer join with new method $lookup in aggregation for mongodb 3.2 and more. Look at documentation

Related

How to query another collection per document in mongoDB

Sorry the title isn't really clear, I was struggling a bit with it.
I'm trying to get posts from all a user's followers using thier IDs
PostModel.find({ author: { $in: arr } }).limit(150).sort({ createdAt: -1 }).exec();
and get the top comments (determined by the number of likes) for each post, the schema for comments is below
Comment Schema
const commentSchema: Schema = new Schema({
author: { type: Schema.Types.ObjectId, ref: 'User' },
parentPost: {type: Schema.Types.ObjectId, ref: 'Post'}, // Post a user is commenting on
createdAt: { type: Date, default: Date.now() },
likedBy: [{type: Schema.Types.ObjectId, ref: 'User'}],
likes: { type: Number, default: 0 },
});
Most of possible solutions I've come across has to do with agreggation but I'm not sure how to apply that here or if it's applicable, please how do I go about this ?
It is quite applicable with $lookup stage in aggregation: Perform a Single Equality Join with $lookup

Mongoose find documents based on subdocument reference value

I am trying to grab documents based on subdocuments reference.
I have tried
Blog.find({"user.blocked" : false})
that query doesn't pull any documents results.
Here are my Schemas
const BlogSchema = new mongoose.Schema({
category: {type: String, trim: true},
user: {type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true},
title: {type: String},
description: {type: String},
}, {timestamps: true});
const UserSchema = new mongoose.Schema({
name: {type: String, required: true},
blocked: Boolean,
}, {timestamps: true});
mongoose.model('User', UserSchema);
mongoose.model('Blog', BlogSchema);
You are defining user as a reference, so you cannot query on fields of other collection. This is one of the differences with relational Databases, you cannot perform a JOIN.
Your alternative is to use an aggregation instead of a query, using the $lookup operator. You can check about it here

How to set a foreign key in mongoose?

I need to set a field from another collection as a foreign key to my mongoose schema.
I have a counter pid to productSchema. I need to set pid as a foreignkey to orderSchema
const orderSchema = mongoose.Schema({
id: mongoose.Schema.Types.ObjectId,
product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product',
required:
true },
quantity: { type: Number, default: 1 }
});
const productSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true },
price: { type: Number, required: true },
productImage: { type: String }
});
Well MongoDB is not a relational DB so it does not support concepts like foreign key. In mongoDB you have to structure your data in such a way that you can fetch information easily.
You should see if you can go with Aggregation or something but mongoDB does not have foreign keys. More important you should make correct choice when you are creating a DB , you should select appropriate DB according to your requirements.

How to populate the model of populated model in mongoose

I come from the MySQL background. I am new to MongoDB. How can I get the details model of a populated model? Please help me
Listing Model
var listing = new mongoose.Schema({
ru_id : [{type: mongoose.Schema.Types.ObjectId, ref: 'Rentable_unit' }],
pro_id : [{type: mongoose.Schema.Types.ObjectId, ref: 'Property' }]
})
Property Model
var property = new mongoose.Schema({
address_id : [{type: mongoose.Schema.Types.ObjectId, ref: 'Address' }],
pro_authority : [{type : mongoose.Schema.Types.ObjectId, ref: 'User' }]
})
Address Model
var address = new mongoose.Schema({
address_line_1: { type: String },
address_line_2: { type: String }
})
I need to get the data from listing address based on property how can I do this.
You will have to load your listing, then your property and then the address with three queries. It's referenced in the article below as application-level join.
If you need to do this a lot you should consider changing your schema design. You could check this blog post from mongodb for possible solutions.

MongoDB performances $ref vs embedded

I recently started a project using mongodb and nodejs to build a restful web service. Unfortunately mongodb is very new to me, and coming from the relational databases world I'm asking my self a lot of questions.
Let me explain you my problem :
The goal is to build a sort of content management system with social features like a user can post topics that can be shared and commented.
I have 2 possibilities to do this the one using a reference to get topics posted by a user, the second using topics as embedded document of user instead of reference.
So basically I can have these 2 schemas :
var UserSchema = new Schema({
username: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
name: {
type: String
},
first_name: String,
phone: String,
topics: [Topic.schema]
});
var TopicSchema = new Schema({
_creator: {
type: String,
ref: 'User'
},
description: String,
comments: [Comments.schema],
shared_with: [{
type: Schema.ObjectId,
ref: 'User'
}] //[{ type: String, ref: 'User'}]
});
var CommentSchema = new Schema({
_creator: {
type: String,
require: true
},
text: {
type: String,
required: true
},
});
and
var UserSchema = new Schema({
username: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
name: {
type: String
},
first_name: String,
phone: String,
topics: [{ type: Schema.ObjectId, ref: 'Topics'}]
});
var TopicSchema = new Schema({
_creator: {
type: String,
ref: 'User'
},
description: String,
comments: [Comments.schema],
shared_with: [{
type: Schema.ObjectId,
ref: 'User'
}] //[{ type: String, ref: 'User'}]
});
var CommentSchema = new Schema({
_creator: {
type: String,
require: true
},
text: {
type: String,
required: true
},
});
So the first schema uses 1 collection of user document and the second use 1 collection for the user and 1 collection for the topics, this implies to make for example, 2 finds queries to retrieve a user and it's topics but it is also easyer to query directly the topics.
Here is the request I use to retrieve a specific topic with some user info with the first schema :
User.aggregate([
{$match: {
"topics._id":{$in:[mongoose.Types.ObjectId('56158c314861d2e60d000003')]}
}},
{ $unwind:"$topics" },
{$match: {
"topics._id":{$in:[mongoose.Types.ObjectId('56158c314861d2e60d000003')]}
}},
{ $group: {
_id: {
_id:"$_id",
name:"$name",
first_name:"$first_name"
},
topics:{ "$push": "$topics"}
}}
]);
So the question is, what do youh think ? Which is the good schema in your opinion ?
Thanks in advance.
Better solution: using a reference to get topics posted by a user
For this database use, one typically needs to consider the MMAPV1 document size limit (16MB). Putting user, topic, and comments in one document allows the document to grow without bound. If each topic is a page of text (1K), then each user could have about 16,000 topics before the limit is reached. That seems huge, but what happens if you decide to put images, videos, sounds in the topic as the product matures? Converting from an embedded to a normalized schema later would be a lot more work than a simple design choice today.
Similarly, if the comments could grow to cause a topic to exceed the 16MB limit, they should be in a separate collection. Unlikely? Probably. But if you are writing something that will become, say, the Huffington Post - check out comments on their popular articles.
Here is mongo's advice on data model design

Resources