Need help to make mongo $lookup query - mongodb

This is my table structure
Group -> _id,name,description,type
GroupMembers -> _id, group(FK),status,Isinvited, user_id(Fk)
User -> _id,name,email,role
Need :- I want to get groups with its active members (status = true) aslo need the name of users from User collections
Current Code :-
Group.aggregate([
{
$lookup: {
from: "groupmembers",
localField: "_id",
foreignField: "group",
as: "membersList"
}
},
{
$lookup : {
from: "users",
localField: "membersList.user",
foreignField: "_id",
as: "userss"
}
},
{
$match:{"_id" : mongoose.Types.ObjectId("5abe70eb7ede1b695e9342d6")}
},
{
$project:{"_id":1,"name":"$name","member":{"membersList":"$membersList","userss":"$userss"}}
}
])
Getting the response but not in well manners go like ->
[
{
"_id": "5abe70eb7ede1b695e9342d6",
"name": "Welcome To Hobnobbin",
"member": {
"membersList":["Got memebrsLiset from GroupMembers"],
"userss": ["Got users from groupMembers FK "]
}
}
]
How can I get it like
[
{
"_id": "5abe70eb7ede1b695e9342d6",
"name": "Welcome To Hobnobbin",
"member": {
"membersList":["Got memebrsLiset from GroupMembers",user: "Userobject here"],
}
}
]
Collections : ->
var GroupSchema = new Schema({
name: {
type: String,
required: 'Please fill Group name',
trim: true
},
photo:{
type:String
},
type: {
type: [{
type: String,
enum: ['child', 'adult']
}],
required: 'Please select at least one type'
},
description:{
type:String,
default:''
},
pinnedTweet:{
type:String,
default:''
},
/*members: [{
type: Schema.ObjectId,
ref: 'User'
}],*/
jointype: {
type: String,
enum: ['openToJoin', 'openToRequest', 'inviteOnly'],
default: 'openToJoin',
required: 'Please select at least one behavious of group'
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
createByHobnob: {
type: Boolean,
default: false
},
isWelcomeGroup: {
type: Boolean,
default: false
},
allowPrivateChat: {
type: Boolean,
default: false
}
});
var GroupMemberSchema = new Schema({
user : {
type: Schema.ObjectId,
ref: 'User'
},
group : {
type: Schema.ObjectId,
ref: 'Group'
},
role: {
type: String,
enum: ['member', 'ban', 'moderator', 'admin'],
default: 'member',
required: 'Please select at least one role'
},
is_active: {
type: Boolean,
default: false
},
is_invited: {
type: Boolean,
default: false
},
created: {
type: Date,
default: Date.now
},
allowChat: {
type: Boolean,
default: true
}
});
var UserSchema = new Schema({
firstName: {
type: String,
trim: true,
default: ''
},
lastName: {
type: String,
trim: true,
default: ''
},
displayName: {
type: String,
trim: true
},
email: {
type: String,
unique: true,
lowercase: true,
trim: true,
default: '',
validate: [validateLocalStrategyEmail, 'Please fill a valid email address']
}
});

Related

Mongodb mongoose join two collection and fetch data

schema:
var UserSchema = new Schema({
id: { type: String, unique: true },
username: { type: String, unique: true },
password: String,
first_name: String,
last_name: String,
email: { type: String, unique: true },
phone: { type: String, unique: true },
status: { type: Boolean, default: false },
role: {
type: String,
enum: ["REGULAR", "ADMIN", "SUPER-ADMIN", "OPERATOR"],
default: "REGULAR",
},
tenantRef: { type: Schema.Types.String, ref: "tenant" },
teamRef: { type: Schema.Types.String, ref: "team" },
customerRef: { type: Schema.Types.String, ref: "customer" },
created: { type: Date, default: Date.now },
});
var CustomerSchema = new Schema({
id: { type: String, unique: true },
name: String,
plan: String,
billing: String,
status: { type: Boolean, default: true },
created: { type: Date, default: Date.now },
});
controller:
userController.getUsers = async function (req, res) {
const users = await UserSchema.find({}).populate({
path: "teamRef",
});
console.log(users);
return res.status(200).send(users);
};
Here i am trying to join user and customer so that i can get customer name along with user data .
I am using above way but it is not working.
Please take a look how can i do it

populate or aggregator, how?

I want to get only all messages related to the projects posted by user.
I don't think there is a way to do so using populate because we have to get the user id from the other collection and then render messages using his id which is "submittedBy" in the project schema.
I am trying aggregator but it is also not working.
Any help or clue would be appreciated.
message Schema:
const MessageSchema = new Schema({
content:{
type: String,
trim: true
},
projectId:{
type: Schema.Types.ObjectId,
ref: 'Form'
},
imageId:{
type: Schema.Types.ObjectId,
ref: 'Image'
},
sender:{
type: Schema.Types.ObjectId,
ref: 'User'
},
readBy:[{
type: Schema.Types.ObjectId,
ref: 'User'
}],
}, {timestamps:true});
Project schema:
const FormSchema = new Schema({
submittedBy: {
type: Schema.Types.ObjectId,
ref: 'User'
},
logoName: {
type: String,
trim: true
},
industry: [{
type: String,
trim: true
}],
logoType: [{
type: String,
trim: true
}],
colors: [{
type: String,
trim: true
}],
tagline: {
type: String,
trim: true
},
org: {
type: String,
trim: true
},
communicate: {
type: String,
trim: true
},
deadline : {
type: String,
trim: true
},
services: {
type: String,
trim: true
},
package: {
type: String,
trim: true
},
assignedTo: {
type: String,
trim: true
}
}, {timestamps:true})
I tried population but I don't think it will work or efficient.
So I am using aggregation but it's not working:
var objId = mongoose.Types.ObjectId(req.session.user._id);
results = await Model.aggregate([
{
$lookup:
{
from: "forms",
localField: "projectId",
foreignField: "_id",
as: "tags"
}
},
{ $unwind: "$tags" },
{$match:{ 'tags.submittedBy': userId }},
]).exec(function(err, results) {
console.log(results)
});
Result After Combining two collections:
{
_id: 609bd3772583c56dd3e302d3,
readBy: [],
content: 'Remove Tagline and align.',
sender: 604db5708cf232652cd4469e,
imageId: 6099964c2583c56dd3e302c3,
projectId: 60968eed2583c56dd3e302ac,
createdAt: 2021-05-12T13:09:11.060Z,
updatedAt: 2021-05-12T13:09:11.060Z,
__v: 0,
tags: {
_id: 60968eed2583c56dd3e302ac,
industry: [Array],
logoType: [Array],
colors: [Array],
logoName: 'global consultancy services',
tagline: 'Follow your dreams',
org: 'We guide students who seeks to study overseas e.g. the UK. We offer consultancy services to students from selecting a university to getting visa and then getting in the country.',
communicate: '3 concepts\r\n' +
'Keep "Indra global " big AND bold\r\n' +
'and "consultancy services" below it.\r\n' +
'In one concept you can use IGCS initials to create icon form'
deadline: '2021-05-12',
services: '',
package: 'undefined',
submittedBy: 60968eed2583c56dd3e302ab,
createdAt: 2021-05-08T13:15:25.661Z,
updatedAt: 2021-05-10T08:28:18.587Z,
__v: 0,
assignedTo: '6050d8485cc8bb6a20ef36fa'
}
}
]

MongoDB/Mongoose Schema for checking room availability

I've following schema for a Hotel room.
const { Schema, model } = require('mongoose');
const reservationSchema = new Schema({
checkIn: {
type: Date,
require: true
},
checkOut: {
type: Date,
require: true
},
status: {
type: String,
require: true,
enum: ['pending', 'cancel', 'approved', 'active', 'completed']
}
});
const roomSchema = new Schema(
{
title: {
type: String,
required: true
},
slug: {
type: String
},
description: {
type: String,
required: true
},
capacity: {
adults: {
type: Number,
required: true
},
childs: {
type: Number,
default: 0
}
},
roomPrice: {
type: Number,
required: true
},
gallery: [
{
type: String,
require: true
}
],
featuredImage: {
type: String,
require: true
},
reservations: [reservationSchema],
isAvailable: {
type: Boolean,
default: true
},
isFeatured: {
type: Boolean,
default: false
},
isPublish: {
type: Boolean,
default: false
}
},
{ timestamps: true }
);
module.exports = model('Room', roomSchema);
Now I want to find rooms which are not reserved for a particular date period.
Example: If the search query is checkIn: 12/25/2019 and checkOut:12/30/2019 then the query result will show that rooms which are not reserved for this period. Also, it will show the reserved room if the reservation status is canceled.
How can I achieve this?
Do I need to change the Schema design for achieving this?

Associate one schema with another

I have my user schema:
const userSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
date: { type: Date, default: Date.now },
active: { type: Boolean, default: false }
});
I want to create a leave status schema. Data will be given by only one user about all leave status. I want to associate each one of the leave status to there respective user schema id. I tried leave status schema as the following:
const leaveSchema = new Schema({
leave: [
{
email: { type: String, required: true },
month: { type: String, required: true },
year: { type: Number, required: true },
earnedleave: { type: Number },
sickleave: { type: Number },
festivalleave: { type: Number },
compoff: { type: Number }
}
]
});
How can i associate my emailid with userschema. Can it be possible? If so, how can i tweak it?
We don't need to associate the schema to get leave based on user, You can use aggregation for that,
db.user.aggregate([
...
{$lookup: {from: "leave", localField: "email", foreignField: "leave.email", as: "leaves"}},
...
]);
Still, If you like to associate two collection, You have to use ref using ObjectId
const leaveSchema = new Schema({
leave: [
{
user: { type: Schema.Types.ObjectId, ref: 'user' }, //Your model name as reference
email: { type: String, required: true },
month: { type: String, required: true },
year: { type: Number, required: true },
earnedleave: { type: Number },
sickleave: { type: Number },
festivalleave: { type: Number },
compoff: { type: Number }
}
]
});

$lookup work in MongoDB but doenst work with mongoose

I have two Documents:
Category = new Schema({
storeKey: { type: String, required: true },
cod: { type: String, required: true },
name: { type: String, required: true },
visible: { type: Boolean }
},
{
timestamps: {
createdAt: "created",
updatedAt: "updated"
}
}
);
and:
Product = new Schema({
name: { type: String, required: true },
cod: String,
storeKey: { type: String, required: true },
categoryId: String,
description: { type: String, required: true },
price: { type: Number, required: true },
stockQuantity: { type: Number, required: true },
avatar: String,
visible: Boolean
}, {
timestamps: true
});
Query on server whith mongoose to locate products with the aggregate category
Product.aggregate([
{
$lookup: {
from: "Category",
localField: "categoryId",
foreignField: "_id",
as: "category"
}
}]
).exec((error, done) => {
if (error) res.status(500).send({
message: langs[req.query.lang],
error
});
res.status(200).send(done);
});
query on local terminal
db.Product.aggregate(
[{
$lookup: {
localField: "categoryId",
from: "Category",
foreignField: "_id",
as: "category"
}
}])
In the terminal, $lookup works correctly. With mongoose, it brings duplicate records and does not bring existing categories. What is wrong?
#Anthony Winzlet was correct, should be categories (in the pural) would have to leave categories (in the pural) and not category, but also, i had not defined the categoryId field as being an ObjectId in the Product Schema, so it was comparing string with ObjectId. In the tests in the terminal I had saved the server return, which returns the _id fields as strings. Now it's working.Thanks!
const ProductSchema = new Schema({
name: { type: String, required: true },
cod: String,
storeKey: { type: String, required: true },
categoryId: { type: Schema.Types.ObjectId, ref: 'categories' },
description: { type: String, required: true },
price: { type: Number, required: true },
stockQuantity: { type: Number, required: true },
avatar: String,
visible: Boolean
}, {
timestamps: true
});