Mongoose many to many relationship - node.js

I am completely new to Node.js and Mongoose and I came up to this problem of having
Event and User and a relationship where the User can go to any Event and Event can have many participating users.
Any time the user would want to attend an Event I could add the Event id to User's array of events and simultaneously add the User to the Event's array of users but I think that I want to avoid this approach because I would store the same information twice.
On the other hand I could only store the User to the Event's array of users and use virtual mapping to retrieve all the User's events but I find this approach quite time consuming. It seems to me that I would have to go through each Event and then through all of its participating users to find out if the user really is participating or not. Anyways if there is a way to do this using the virtual function, i don't know how to map the localField: userId to the array of the Event's foreignField: participants.
What would be the correct approach to this problem?

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const eventSchema = Schema({
name: String,
user: [{ type: Schema.Types.ObjectId, ref: 'User' }]
});
const userSchema = Schema({
name: String,
event: [{ type: Schema.Types.ObjectId, ref: 'Event' }]
});
const Event = mongoose.model('Event', eventSchema);
const User = mongoose.model('User', userSchema);
use can read more here https://mongoosejs.com/docs/populate.html

Related

Schema design suitable for big system

I am designing a follow feature for my online books reading which had about 100k books. So I wonder which is a better way to use MongoDB.
Push all books followed into array and store as 1 document. When reach max document we split into another document
When the user followed a book we create a need documents
Please help me point out the Pros and Cons of each way or a new way better than both above way to reach this situation
const mongoose = require('mongoose');
const {comicConnection} = require('../db');
const Schema = mongoose.Schema;
const UserFollowsSchema = new Schema(
{
userId: { type: Schema.Types.ObjectId, ref: 'Users' },
follow: [{ type: Schema.Types.ObjectId, ref: 'Books' }],
},
{
timestamps: true,
}
);
module.exports = comicConnection.model(
'UserFollows',
UserFollowsSchema,
'UserFollows'
);
It is better to use the second method, you have better access and you can do calculations more easily.
Whenever a user follows a book, create a document that the user follows the book, and so on.
Then you can use this to find out how many books you have followed:
User.countDocuments({user:{USER-ID}});

Mongoose populate schema from different Database

For example i have SchemaA and SchemaB which both belong to different database. Inside SchemaA i have doc.b = {type: mongoose.Schema.Types.ObjectId, ref: 'SchemaB'}. When i am doing populate of this i got below error. MissingSchemaError: Schema hasn't been registered for model "SchemaB". Use mongoose.model(name, schema) From my research i have read that mongoose support population cross databases.
I am requiring mongoose multiple times for each schema, is that the problem?
Basically what i need is two different schema which is connecting to different databases to work together with populate. If i register schema on connection created by mongoose they will not be registered on the same list. If there a way to success that?
Basically what we need to do is pass schema to population, something like this:
User.findOne({
_id: req.user._id
}).populate({
path: 'roomsContainer',
model: RoomsContainer,
populate: [{
path: 'creator'
},{
path: 'users'
},{
path: 'rooms',
model: Room
}]
}).exec(function(err, user) {
// do some magic
});
Where User belong to database one and Room, RoomsContainer belong to database two.
const db1 = mongoose.createConnection('mongodb://localhost:27000/db1');
const db2 = mongoose.createConnection('mongodb://localhost:27001/db2');
const conversationSchema = new Schema({ numMessages: Number });
const Conversation = db2.model('Conversation', conversationSchema);
const eventSchema = new Schema({
name: String,
conversation: {
type: ObjectId,
ref: Conversation // `ref` is a **Model class**, not a string
}
});
const Event = db1.model('Event', eventSchema);
Refrence here

One-To-Many relation in MongoDB

At the moment I am looking at mongoDB. I try to implement a simple one-to-many relation using nodejs and mongoose:
Model/Schema User:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var UserSchema = new Schema({
name: String
});
module.exports = mongoose.model('User', UserSchema);
Model/Schema Article:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ArticleSchema = new Schema({
name: {
type: String,
required: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
module.exports = mongoose.model('Article', ArticleSchema);
So my question, now:
How can I get all Users including its Articles?
Do I really have to add a ref to my UserScheme, too? What is the best-practice in an one-to-many relation like this? Is there something like a join in mongodb?
One User has many Articles - an Article belongs to one User.
Calling something like /user/:user_id , I want to receive the user with _id=user_id containing all of his articles.
That is the most horrible idea, for various reasons.
First, there is a 16MB BSON document size limit. You simply can not put more into a document. Embedding documents is rather suited for "One-to-(VERY-)Few" relationships than for a "One-to-Many".
As for the use case: What is your question here? It is
For a given user, what are the articles?
REST wise, you should only return the articles when /users/:id/articles is GETed and the articles (and only the articles) should be returned as a JSON array.
So, your model seems to be natural. As for the user:
{
_id: theObjectId,
username: someString
…
}
and an article should look like this:
{
_id: articleIdOrSlugOrWhatever,
authors: [theObjectId],
// or author: theObjectId
retention: someISODate,
published: someOtherISODate
}
So when your REST service is called for /users/:id you'd simply look up
var user = db.users.findOne({_id:id})
And when /users/:id/articles is called, you'd lookup
var articles = db.articles.find({author:id})
Problem solved in a scalable way, adhering to REST principles.

How to implement a "follows"/has-many relationship with mongoosejs?

I am creating an app with mongoose and express.I have user and venue models.
I want users to follow venues and view all the venues they are following. I also want to display all users following a venue on the venue's page. A user follows many venues and a venue has many user followers.
What is the best way to implement this relationship with the mongoose ORM? What should my models look like? What about the CRUD following operations?
I have seen mongoose-relationship but it does not seem very popular. What is the mongoose.js community solution to implementing this "following" database relationship?
the user model/Schema will have an "venuesFollowing" array containing venue._id's. The venue model/Schema will have a "usersFollowing" array containing user._id's.
var Mongoose = require('mongoose');
var Schema = Mongoose.Schema;
var Venue = require('./venue');
var userSchema = new Schema({
fullName: {type: String, required: true},
username: {type: String, required: true},
email: {type: String, required: true},
venuesFollowing: [{type: Mongoose.Schema.ObjectId , ref: 'Venue'}],
});
var User = Mongoose.model("User", userSchema);
module.exports = User;
You can use this user model as a basis to construct your venue model and substituting the venuesFollowing with users following. You are requiring the Venue model so that it can be referenced in this user model and vice-versa. You will be able to access all of the users following a venue by their ID's and vice-versa for the the users and the venue id's that they follow.

How would I develop a relationship User belongs to Groups in Mongoose & Node.js?

I am trying to teach myself node.js, coming from Rails, and I want to establish this relationship:
A group has_many users, a user belongs_to group
How would I go about doing this in my models?
//for user
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
name: String
});
module.exports = mongoose.model('User', UserSchema);
//for group
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var GroupSchema = new Schema({
name: String
});
module.exports = mongoose.model('Group', GroupSchema);
Also I would like to allow a moderator to kick someone out of a group if the person were obnoxious. How could I target a user belonging to a group and then delete the user. It seems more complicated than the traditional CRUD methods. Do I need nested resources like in rails, or the equivalent?
Mongoose has a feature called population that you can use to set up "relationships" (MongoDB only has limited support for relationships).
Your schema would look something like this:
var UserSchema = new Schema({
name : String,
group: { type: Schema.Types.ObjectId, ref: 'Group' }
});
var GroupSchema = new Schema({
name : String,
users : [ { type: Schema.Types.ObjectId, ref: 'User' } ]
});
In other words: the User model has a group property which points to the group the user belongs to, and the Group model has a users property (an array) that contains references to the users that belong to the group.
To associate a user to a group (assuming that group is a variable that is a Group instance):
user.group = group;
user.save(...);
And to add the user to a group:
group.users.push(user);
group.save(...);
However, you should be aware that array properties in MongoDB documents have limited scalability. I think that a few dozen items in an array will work just fine, but when the number of users in a group are expected to be in the thousands, this probably won't be a viable solution. In that situation, you probably should consider a "junction collection" (similar to SQL's "junction table").
To remove a user from a particular group, I think you need to use .update():
Group.update({ _id: group._id }, { $pull : { users : user._id }})

Resources