Home > other >  Mongoose model schema referencing each other - how to simplify?
Mongoose model schema referencing each other - how to simplify?

Time:12-05

I am using mongoose and have two schemas: UserSchema and CommunitySchema:

const UserSchema = new Schema({
  name: String,
  communities: [{ type: Schema.Types.ObjectId, ref: CollectionModel }],
  exCommunities: [{ type: Schema.Types.ObjectId, ref: CollectionModel }],
}, { timestamps: true });

const CommunitySchema = new Schema({
  slug: { type: String, unique: true },
  name: String, 
  description: String, 
  users: [
    { type: Schema.Types.ObjectId, ref: "User" }
  ]
}, { timestamps: true });

User can be a part of multiple communities and also leave any community and be in the exCommunities field.

When an user joins a community, I have to do a double work: Add the user to a user community and update the community user field with the reference ID.

Questions:

  1. Is there a way to simplify it? For example, by managing the CommunitySchema users field automatically based on the UserSchema communities field?

Now I have to do this:

   collection.users.push(userId);
   user.communities.push(communityId);

Could the collection.users be automatically added when I push a community to user.communities? And how?)

  1. Is it possible to add a date when the user is added to a community or leave a community? Something like: communities: [{ type: Schema.Types.ObjectId, ref: CollectionModel, createdAt: "<DATE>" }]

Thank you!

CodePudding user response:

you no need to add communities and exCommunities in UserSchema

const UserSchema = new Schema({
   name: String,
}, { timestamps: true });

const communityUserSchema = new Schema({
   user_id:{type: Schema.Types.ObjectId, ref: "User"},
   joined_at:{type:Date},
   leaved_at:{type:Date},
   is_active:{type:Boolean},
   role:{type:String, enum:['user','admin'], default:'user'}
});

const CommunitySchema = new Schema({
  slug: { type: String, unique: true },
  name: String, 
  description: String, 
  users:{
    type:[communityUserSchema],
    default:[]
  }
}, { timestamps: true });

you can find User's communities by :

let user_id = req.user._id;
all_communities = await Community.find({"users.user_id":user_id});

active_communities = await Community.find({"users.user_id":user_id, "is_active":true});

ex_communities = await Community.find({"users.user_id":user_id,"leaved_at":{"$ne":null}});

When User Create New Community (create as a Admin):

let current_user = {user_id:req.user.id,joined_at:new Date(),is_active:true,role:'admin'};

 //  if you select users from frontend while creating new community  

 let other_user = req.body.user_ids;
 let other_users_mapped = other_user.map((item)=>{ return {user_id:item,joined_at:new Date(),role:'user',is_active:true}}); 

 let all_users = [current_user];
 all_users = all_users.concat(other_users_mapped);

 let community = new Community();
  community.name = req.body.name;
  community.slug = req.body.slug;
  community.description = req.body.description;
  community.users = all_users ;
  let created = await community.save();

When User Leave Community :

Community.updateOne({_id: community_id , 'users.user_id':user_id },{
   $set:{
       'users.$.is_active':false,
       'users.$.leaved_at':new Date()
   }
});

View Community with only active members :

let community_id = req.params.community_id;
let data = await Community.findOne({_id:community_id},{ users: { $elemMatch: { is_active: true } } });

CodePudding user response:

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.

  • Related