Mongoose Complex Query by Subdocument - node.js

I need to find a Project by either Owner, Manager, or one of the Team Members. Here's how the schema looks like:
var project = new mongoose.Schema({
title: { type: String, require: true },
slug: { type: String, require: true },
description: { type: String, require: true },
descriptionHtml: { type: String, require: true },
nextVanityId: { type: Number, default: 1 },
owner: { type: ObjectId, ref: 'Member', require: true },
teams: [{ type: ObjectId, ref: 'Team' }],
managers: [{ type: ObjectId, ref: 'Member' }]
};
var team = new mongoose.Schema({
name: { type: String, require: true },
slug: { type: String, require: true },
project: { type: ObjectId, require: true, ref: 'Project' },
created: { type: Date, require: true, default: Date.now },
members: [{ type: ObjectId, default: null, ref: 'Member' }]
};
My query method looks like this:
function findByMember (member, done) {
var id = member._id;
Project
.find()
.or([
{ owner: id },
{ managers: id },
{ 'teams.members': id }
])
.exec(done);
}
Currently it works for both owners and managers, but I'm drawing blanks when querying the members collection of each team. What should I use?

In order for your query to work you can approach the problem in 2 ways.
Solution 1
Have your teams as an embedded document in projects:
var team = new mongoose.Schema({
name: { type: String, require: true },
slug: { type: String, require: true },
project: { type: ObjectId, require: true, ref: 'Project' },
created: { type: Date, require: true, default: Date.now },
members: [{ type: ObjectId, default: null, ref: 'Member' }]
};
var project = new mongoose.Schema({
title: { type: String, require: true },
slug: { type: String, require: true },
description: { type: String, require: true },
descriptionHtml: { type: String, require: true },
nextVanityId: { type: Number, default: 1 },
owner: { type: ObjectId, ref: 'Member', require: true },
teams: [team],
managers: [{ type: ObjectId, ref: 'Member' }]
};
This way your project document will have the team information and the teams.members makes sense.
Solution 2
Denormalise your Team data to have only the relevant information embedded:
var team = new mongoose.Schema({
name: { type: String, require: true },
slug: { type: String, require: true },
project: { type: ObjectId, require: true, ref: 'Project' },
created: { type: Date, require: true, default: Date.now },
members: [{ type: ObjectId, default: null, ref: 'Member' }]
};
var project = new mongoose.Schema({
title: { type: String, require: true },
slug: { type: String, require: true },
description: { type: String, require: true },
descriptionHtml: { type: String, require: true },
nextVanityId: { type: Number, default: 1 },
owner: { type: ObjectId, ref: 'Member', require: true },
teams: [{
_id: { type: ObjectId, ref: 'Team' },
members: [{ type: ObjectId, default: null, ref: 'Member' }]
}],
managers: [{ type: ObjectId, ref: 'Member' }]
};
In this second approach you need to keep the Team document and the denormalised data in sync.

Related

Creating Two Foreign key mongoose inside a controller

Hi I want to implement this snippet of my class diagram using mongoose.
Here is my logic model in detail:
Here is the definition of my Mother model:
const mongoose = require('mongoose')
const motherSchema = mongoose.Schema({
cniMother: { type: Number, required: true },
name: { type: String, required: true },
surname: { type: String, required: true },
birthDay: { type: Date, required: true },
birthPlace: { type: String, required: true },
address: { type: String, required: true },
phone: { type: Number, required: true },
occupation: { type: String, required: true },
});
module.exports = mongoose.model('Mother', motherSchema);
Here is the definition of my Declared model:
const mongoose = require('mongoose')
const declaredSchema = mongoose.Schema({
name: { type: String, required: true },
surname: { type: String, required: true },
father: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Father',
//required: true,
},
mother: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Mother',
//required: true,
},
birthDay: { type: Date, required: true },
birthPlace: { type: String, required: true },
gender: { type: String, required: true },
nationality: { type: String, required: true }
});
module.exports = mongoose.model('Declared', declaredSchema);
I want to retrieve the name of the father and the mother corresponding to the declared.
Can anyone help me please?

MongoDB Many to many relationship reference with extra fields

I have 2 models - User & Project.
Relations are -
Users can have multiple projects (One to many)
One projects may be shared with multiple other users. (Many to many)
const UserSchema = new Schema({
name: {
type: String,
required: true,
},
mobile: {
type: Number,
required: true,
unique: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true,
},
role: {
type: String,
default: 'basic',
enum: ["basic", "admin"]
},
projects: [
{
type: Schema.Types.ObjectId,
ref: 'Project'
}
],
shared_projects: [
{
type: Schema.Types.ObjectId,
ref: 'Project'
}
]
}, { timestamps: true });
const ProjectSchema = new Schema({
name: {
type: String,
required: true,
},
active: {
type: Boolean,
default: false,
},
expiry: {
type: Date,
default: null,
},
owner: {
type: Schema.Types.ObjectId,
ref: 'User'
},
shared_users: [
{
type: Schema.Types.ObjectId,
ref: 'User'
}
]
}, { timestamps: true });
I want to have a feature that the owner of the project may disable one or many shared user. So, I need a status field in ProjectSchema like -
shared_users: [
{
type: Schema.Types.ObjectId,
ref: 'User'
},
status: {
type: Boolean,
default: true
}
]
So, do I need to have the same definition in UserSchema also & update both schemas when user disable or enable a shared user?

How can i calculate daily, weekly or monthly sales from my MongoDB data?

Here is my orders schema with Javascript mongoose;
import mongoose from 'mongoose';
const orderSchema = new mongoose.Schema(
{
orderItems: [
{
name: { type: String, required: true },
qty: { type: Number, required: true },
image: { type: String, required: true },
price: { type: Number, required: true },
product: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Product',
required: true,
},
},
],
shippingAddress: {
fullName: { type: String, required: true },
address: { type: String, required: true },
city: { type: String, required: true },
postalCode: { type: String, required: true },
country: { type: String, required: true },
lat: Number,
lng: Number,
},
paymentMethod: { type: String, required: true },
paymentResult: {
id: String,
status: String,
update_time: String,
email_address: String,
},
itemsPrice: { type: Number, required: true },
shippingPrice: { type: Number, required: true },
taxPrice: { type: Number, required: true },
totalPrice: { type: Number, required: true },
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
seller: { type: mongoose.Schema.Types.ObjectID, ref: 'User' },
isPaid: { type: Boolean, default: false },
paidAt: { type: Date },
isDelivered: { type: Boolean, default: false },
deliveredAt: { type: Date },
},
{
timestamps: true,
}
);
const Order = mongoose.model('Order', orderSchema);
export default Order;
And for the case of sellers how could I do the same for specific sellers.
I would like to create charts and graphs with that data so any help counts. Thank You!

Mongoose/MongoDB Empty SubSchema Array

I have a model in Mongoose that looks like this:
const orderLogSchema = mongoose.Schema(
{
removed: { type: String, required: true },
},
{
timestamps: true,
}
)
const orderSchema = mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
orderItems: [
{
name: { type: String, required: true},
qty: { type: Number, required: true},
image: { type: String, required: true},
price: { type: Number, required: true},
product: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'Product'},
}
],
shippingAddress: {
address: { type: String, required: true },
city: { type: String, required: true },
postalCode: { type: String, required: true },
country: { type: String, required: true },
},
paymentMethod: {
type: String,
required: true,
},
paymentResult: {
id: { type: String },
status: { type: String },
update_time: { type: String },
email_address: { type: String },
},
taxPrice: {
type: Number,
required: true,
default: 0.0
},
shippingPrice: {
type: Number,
required: true,
default: 0.0
},
totalPrice: {
type: Number,
required: true,
default: 0.0
},
isPaid: {
type: Boolean,
required: true,
default: false
},
paidAt: {
type: Date,
},
isDelivered: {
type: Boolean,
required: true,
default: false
},
deliveredAt: {
type: Date,
},
couponCode: {
type: Object,
required: false
},
orderVerifyLog: [orderLogSchema],
}, {
timestamps: true
})
I need to be able to empty out the orderVerifyLog which is populated with the orderLogSchema. I have tried a bunch of things most recently I pulled the order into a variable, and I am able to access orderVerifyLog by using order.orderVerifyLog but I cant figure out how to empty out that orderLogSchema. I tried:
order.orderVerifyLog = []
order.save()
Is there an easy way to work with that "sub" schema and zero it out?
Basically I am pulling the log items from that schema for an order and displaying them on my front-end. Then I was to fire off an action to clears it out so they don't display every time the order is loaded (Only want them to show once). I also tired to loop over each item in the orderVerifyLog and use pull to remove them, but for some reason it always leaves one in there.

Save to mongDB 3rd level nested array of objects

I am trying to save data into a teams database with the following model sample. This is a 3rd level nested Array of Objects for MongoDB using Mongoose.
const teamSchema = new Schema({
name: {
type: String,
required: true
},
who: {
type: String,
required: true
},
textManifesto: {
type: String,
required: false
},
videoManifesto: {
type: String,
required: false
},
competencies: {
competency: [{
type: Schema.Types.ObjectId,
ref: 'Competency',
required: true
}]
},
members: [{
member: {
type: Schema.Types.ObjectId,
ref: 'Applicant',
required: true
},
position: {
type: String,
required: true
},
memberCompetencies: {
competency: [{
type: Schema.Types.ObjectId,
ref: 'Competency',
required: true
}]
},
evaluatedCompetencies: {
competency: [{
type: Schema.Types.ObjectId,
ref: 'Competency',
required: false
}]
}
}],
},
I basically used push method to push the array elements into a variable and then try to save into the database but the database comes up empty for Members.memberCompetencies. It just shows and empty array.
//Map Team Competencies
for (let competency of teamCompetencies) //array is your array variable, i suppose
newTeamCompetencies.push({ competency: competency, _id: mongoose.Types.ObjectId() });
//console.log(newTeamCompetencies);
//Map My Competencies
for (let competency of myCompetencies) //array is your array variable, i suppose
newMyCompetencies.push({ _id: mongoose.Types.ObjectId(), competency: competency });
// console.log(newMyCompetencies);
team = await new Team({
name: teamName,
textManifesto: textManifesto,
who: who,
});
//save collective expected competencies of team
team.competencies = newMyCompetencies;
//save member details
team.members = ({
member: res.locals.applicant._id,
position: 'Leader',
memberCompetencies: newMyCompetencies,
})
team = await team.save();
console.log(team.members);
Expected result
[{"memberCompetencies":{ '0':
{ _id: 5d1e128b2a9f1c74907e5ba9,
competency: '5d1dd97206660707754eefb3' },
'1':
{ _id: 5d1e128b2a9f1c74907e5baa,
competency: '5d1dd9d506660707754eefb4' } },,"evaluatedCompetencies":{"competency":[]},"_id":"5d1e1393f640587531b0fd48","member":"5d19999df6f9c678e891af14","position":"Leader"}]
Actual result
[{"memberCompetencies":{"competency":[]},"evaluatedCompetencies":{"competency":[]},"_id":"5d1e1393f640587531b0fd48","member":"5d19999df6f9c678e891af14","position":"Leader"}]
Found the problem. The model was wrong. Members section of the model should be
members: {
member: {
type: Schema.Types.ObjectId,
ref: 'Applicant',
required: true
},
position: {
type: String,
required: true
},
memberCompetencies: {
competency: [{
type: Schema.Types.ObjectId,
ref: 'Competency',
required: true
}]
},
evaluatedCompetencies: {
competency: [{
type: Schema.Types.ObjectId,
ref: 'Competency',
required: false
}]
}
},
It should be
members: {...}
NOT
members: [{...}]

Resources