How to get model data from nested object - node.js

little bit stuck with mongoose. I want to get all users projects where he's added. Tried few options, but in all of them I receive an empty array. So the main question is it possible somehow to find all project by filtering/finding the Project model?
This is how looks my default response to understand what I'm looking for:
{
"_id": "61a8bc4e8e24f10ac7a7288d",
"name": "Random project",
"description": "Random project desc",
"maxWorkingEmployees": 5,
"status": "Paused",
"createdBy": {
"_id": "61a66578f2dabf7555bcf4ab",
"email": "Henrikas#furniture1.eu",
"role": "Owner"
},
"currentlyWorkingEmployees": [
{
"username": "Ema",
"role": "Employee",
"_id": "61a8e0423140ecce769dc971"
}
],
"createdAt": "2021-12-02T12:30:06.461Z",
"updatedAt": "2021-12-02T15:11:51.361Z",
"__v": 0
}
Project model:
const mongoose = require('mongoose');
const SingleUserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
role: {
type: String,
required: true,
},
});
const ProjectSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, 'Provide project name'],
minlength: 5,
},
description: {
type: String,
required: [true, 'Provide description about the project'],
},
maxWorkingEmployees: {
type: Number,
required: [
true,
'Provide maximum number of employees working on this project',
],
},
currentlyWorkingEmployees: [SingleUserSchema],
status: {
type: String,
enum: ['Pending', 'In progress', 'Paused', 'Delayed', 'Completed'],
default: 'Pending',
},
createdBy: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true,
},
},
{ timestamps: true }
);
module.exports = mongoose.model('Project', ProjectSchema);
Here's my controller and my first try:
const getMyProjects = async (req, res) => {
const userId = req.user.userId;
const projects = await Project.find({
currentlyWorkingEmployees: { _id: userId },
});
res.json({projects});
};
Second shot after reading some articles
const getMyProjects = async (req, res) => {
const userId = req.user.userId;
const projects = await Project.aggregate([
{
$match: {
currentlyWorkingEmployees: { _id: userId },
},
},
]);
};

As I said in the comment you can do it accessing to the internal object of the schema with an string accessing to it child object.
Project.find({'currentlyWorkingEmployees._id': userId})

Related

MissingSchemaError: Schema hasn't been registered for model images

I keep getting the same error that my imageSchema hasn't been registered for ImageModel when I try to populate the posts from UserModel. But I can't figure out what's the issue. I checked the image Schema file and I don't see anything wrong. Or am I missing something else?
User model
const userSchema = new mongoose.Schema(
{
name: {
type: String,
required: true
},
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
min: 6,
max: 30
},
created: {
type: Date,
required: true,
default: Date.now
},
},
{
timestamps: true,
toJSON: {
virtuals: true
}
},
);
userSchema.virtual("posts", {
ref: "ImageModel",
foreignField: 'userId',
localField: '_id'
});
module.exports = mongoose.model('users', userSchema);
Image model
const imageSchema = new mongoose.Schema({
caption: {
type: String,
},
timeCreated: {
type: Date,
default: () => Date.now(),
},
img: {
type: String,
default: 'placeholder.jpg',
},
});
module.exports = mongoose.model("imagesPosts", imageSchema);
model routes
const UserModel = require("../models/User");
const ImageModel = require("../models/Image");
This is the code I'm working on to populate the posts from the User model, but I'm not sure if I'm doing it correctly or not.
const userId = req.user.id;
try {
const result = await UserModel.findById(userId).populate("posts");
console.log("\n\nPopulate result: " + result + "\n\n");
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong, check logs");
}
**Desired output: **
{
"_id": "5e3a885ec511414a3c37a78c",
"username": "Johm",
"email": "john#head.dev",
"password": "123123",
"__v": 0,
"posts": [
{
"_id": "5e3a88e2c511414a3c37a78d",
"caption": "caption one",
"img": "1661309774553spaghetti.jpg",
"userId": "5e3a885ec511414a3c37a78c",
"created": "2020-02-05T09:20:49.754Z",
"__v": 0
},
{
"_id": "5e3a88f1c511414a3c37a78e",
"caption": "caption two",
"img": "1661309774553spaghetti.jpg",
"userId": "5e3a885ec511414a3c37a78c",
"created": "2020-02-05T09:20:49.754Z",
"__v": 0
}
],
}
Declare your posts field as a ref in userSchema:
const userSchema = new mongoose.Schema(
{
posts: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'imagesPosts',
},
],
...
);
You should be able to populate it with:
await UserModel.findById(userId).populate("posts").exec();

soft delete from an array of objects using mongoose

I am trying to soft delete an object from array using mongoose-delete lib
I Have a schema like that :
const mongooseDelete = require('mongoose-delete');
const number = new Schema({
allocation_date: { type: Date, required: true, default: Date.now() },
number: { type: String, required: true },
virtual_number: { type: String, required: true },
virtual_number_id: { type: Number, required: true, unique: true },
});
const schema = new Schema(
{
allocation_id: { type: String, required: true, unique: true },
numbers: { type: [number], required: true },
},
{
timestamps: true,
},
);
number.plugin(mongooseDelete, { deletedAt : true });
exemple data :
{
"_id": "5f7c14f9388ee9ebc0b28abc",
"allocation_id": "5_2_9387323_1"
"numbers": [
{
"allocation_date": "2020-10-06T06:55:41.197Z",
"_id": "5f7c14f997d996f7988fe8cf",
"number": "*********",
"virtual_number": "**********",
"virtual_number_id": *******,
},
{
"allocation_date": "2020-10-06T06:59:41.197Z",
"_id": "5f7c14f997d996f7988fe8cf",
"number": "*********",
"virtual_number": "**********",
"virtual_number_id": *******
}
],
"createdAt": "2020-10-06T06:55:53.367Z",
"updatedAt": "2020-10-06T06:55:53.367Z",
}
When I tried to use the delete method as follow :
const deleteNumber = await VirtualNumberAllocation.findOne(
{
'numbers.virtual_number': virtualNumber.virtualNumber,
allocation_id: virtualNumber.allocationID,
});
const activeVirtualNumber = deleteNumber.numbers.filter(
(number) => number.virtual_number==virtualNumber.virtualNumber,
);
await activeVirtualNumber[0].delete();
I'm getting this error in console:
mongoose: calling `save()` on a subdoc does **not** save the document to MongoDB, it only runs save middleware. Use `subdoc.save({ suppressWarning: true })` to hide this warning if you're sure this behavior is right for your app.
Does anyone have experience with soft deleting from an array using the library?

Problem with the relationship in express/mongoose

Im creating a document named 'Sells', each sell has properties such as date, name, total, the id of the user who created it ect. and I have another document named 'Sell_details' where I store the details of each sell with their sell _id. So how do i retrieve all the sells i have in the database with an array of the details which that sell has? I've tried to do it but it doesn't retrieve all the details and among other problems. Here's what i have.
this is the sell model
const mongoose = require('mongoose');
const validator = require('validator');
const uniqueValidator = require('mongoose-unique-validator');
const ventaSchema = new mongoose.Schema({
usuarioId: {
type: mongoose.Schema.Types.ObjectId,
required: true
},
clienteId: {
type: mongoose.Schema.Types.ObjectId,
required: true
},
tipo_comprobante: {
type: String,
required: true
},
num_comprobante: {
type: Number,
required: true
},
serie_comprobante: {
type: Number,
required: true
},
fecha: {
type: Date,
default: Date.now()
},
impuesto: {
type: Number,
required: true
},
total: {
type: Number,
required: true
},
estado: {
type: String,
default: 'Activo'
},
owner: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
ventas: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Detalle_Venta'
},
detalles: {
type: Array
}
},{ toJSON: { virtuals: true } });
ventaSchema.plugin(uniqueValidator, { message: 'Expected {PATH} to be unique' });
const Venta = mongoose.model('Venta', ventaSchema);
module.exports = Venta;
his is the sell router:
router.get('/ventas', auth, async(req, res) => {
try {
await req.user.populate({
path: 'ventas',
options: {
limit: req.query.limit
}
}).execPopulate();
req.user.ventas.forEach(element => {
const detalles = Detalle_Venta.find({ventaId: element._id});
detalles.then(el => {
el.forEach(detalle => {
if (element.detalles.length > 1) {
element.detalles.forEach(el => {
const isAdded = el._id === detalle._id;
if (isAdded) {
element.detalles.push(detalle);
}
})
} else {
element.detalles.push(detalle);
}
});
});
element.save();
});
res.send(req.user.ventas);
} catch (error) {
res.status(400).send(error);
}
});
and this is the output from postman:
[
{
"fecha": "2020-06-22T18:16:44.175Z",
"estado": "Activo",
"detalles": [
{
"_id": "5ef0fa4e49de0641c46eca0b",
"idArticulo": "5ee825bfb3da101df49822ae",
"cantidad": 30,
"precio": 2,
"descuento": 0,
"ventaId": "5ef0fa4e49de0641c46eca0a",
"__v": 0
},
{
"_id": "5ef0fa4e49de0641c46eca0b",
"idArticulo": "5ee825bfb3da101df49822ae",
"cantidad": 30,
"precio": 2,
"descuento": 0,
"ventaId": "5ef0fa4e49de0641c46eca0a",
"__v": 0
}
],
"_id": "5ef0fa4e49de0641c46eca0a",
"usuarioId": "5ee3b6b50376d7143c476834",
"clienteId": "5ee6b115e43839274cc50ddb",
"tipo_comprobante": "RNC",
"num_comprobante": 1000000,
"serie_comprobante": 20001,
"impuesto": 18,
"total": 10500,
"owner": "5ef0e64083f8c815cc67cd7c",
"__v": 2,
"id": "5ef0fa4e49de0641c46eca0a"
},
{
"fecha": "2020-06-22T18:16:44.175Z",
"estado": "Activo",
"detalles": [
{
"_id": "5ef0fa5a49de0641c46eca0d",
"idArticulo": "5ee825bfb3da101df49822ae",
"cantidad": 30,
"precio": 2,
"descuento": 0,
"ventaId": "5ef0fa5a49de0641c46eca0c",
"__v": 0
},
{
"_id": "5ef0fa5a49de0641c46eca0e",
"idArticulo": "5ee825bfb3da101df49822ae",
"cantidad": 303,
"precio": 2,
"descuento": 0,
"ventaId": "5ef0fa5a49de0641c46eca0c",
"__v": 0
}
],
"_id": "5ef0fa5a49de0641c46eca0c",
"usuarioId": "5ee3b6b50376d7143c476834",
"clienteId": "5ee6b115e43839274cc50ddb",
"tipo_comprobante": "RNC",
"num_comprobante": 1000000,
"serie_comprobante": 20001,
"impuesto": 18,
"total": 10500,
"owner": "5ef0e64083f8c815cc67cd7c",
"__v": 1,
"id": "5ef0fa5a49de0641c46eca0c"
}
]
Before you say i did it, the first array of the 'detalles' array (which stores the sell details of that sell), i added one sell detail and i'm getting two, and the second array of the other sell, i'm getting two sell details but i added 3 and if i add 4 i'm only getting 2 and i don't know why. is there a way to fix it and another best way to do it ?
mongoose has a powerful aggregation operator called populate which you have used.
You should use type ObjectId to the property sell details.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
const storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
Then you create the author and story linking them up
const author = new Person({
_id: new mongoose.Types.ObjectId(),
name: 'Ian Fleming',
age: 50
});
author.save(function (err) {
if (err) return handleError(err);
const story1 = new Story({
title: 'Casino Royale',
author: author._id // assign the _id from the person
});
story1.save(function (err) {
if (err) return handleError(err);
// that's it!
});
});
You can thereafter populate
Story.
findOne({ title: 'Casino Royale' }).
populate('author').
exec(function (err, story) {
if (err) return handleError(err);
console.log('The author is %s', story.author.name);
// prints "The author is Ian Fleming"
});
This will ensure you don't get an entry twice..

I am trying to populate the **task_item** you can see below but I am not getting the result. Nodejs, Expressjs and MongoDb

I am trying to populate the task_item you can see below but I am not getting the result.
{
"msg": "User not exists",
"cart": {
"_id": "5ec0c28cf494113aa06c99d9",
"task_items": [
{
"quantity": 1,
"_id": "5ec0c28cf494113aa06c99da",
**"task_item": "5ebe499d7e657d322c39345f"**
},
{
"quantity": 1,
"_id": "5ec0d018ecc2411cf40bceae",
**"task_item": "5ebe499d7e657d322c39345f"**
},
{
"quantity": 1,
"_id": "5ec0d4abfac25246689d15a7",
**"task_item": "5ec0d4a2fac25246689d15a6"**
}
],
"crreated": "2020-05-17T04:50:20.869Z",
"user": {
"_id": "5ebe4d5d440ab504c8a0d128",
"name": "Ajit",
"phone": "9668854799",
"avatar": "//www.gravatar.com/avatar/20c3d59b7049c9ad85cd33e2ebd3151c?s=200&r=pg&d=mm",
"password": "$2a$10$FdH7QzoqOHnVoLbbm9GaUOLaJbTTqPWzFWeFACkea2NWlrJrFxZ5a",
"createdAt": "2020-05-15T08:05:49.418Z",
"__v": 0
},
"__v": 2
}
}
Below is the Cart.js Model
const monngose = require('mongoose');
const Schema = monngose.Schema;
const CartSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'user'
},
task_items: [{
task_item: {type:Schema.Types.ObjectId, ref: 'SubTaskCategoryItem'},
quantity: { type: Number, default: 1 }
}],
totalPrice: {
type: Number
},
item: {
type: Schema.Types.ObjectId,
ref: 'SubTaskCategoryItem'
},
crreated: {
type: Date,
default: Date.now
}
});
module.exports = monngose.model('Cart', CartSchema);
SubCategoryItem.js - This is the item model
const mongoose = require('mongoose');
const SubTaskItemSchema = new mongoose.Schema({
subtaskItemName: {
type: String,
required: true,
unique: true,
trim: true
},
subtaskItemImage: {
type: String
},
subtaskItemTime: {
type: String
},
description: {
type: String,
trim: true
},
subtaskItemPrice: {
type: String
},
subtaskItemStatus: {
type: Boolean,
default: true
},
subtask: {
type: mongoose.Schema.ObjectId,
ref: 'SubTask',
required: true
},
createdAT: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model("SubTaskCategoryItem", SubTaskItemSchema);
Here I am trying to populate - cart.js router
const express = require('express');
const Cart = require('../../models/admin/Cart');
const checkJwt = require('../../middleware/admin/user_auth');
const TaskItem = require('../../models/admin/SubTaskCategoryItem');
const router = express.Router();
router.post('/add_cart', checkJwt, (req, res, next) => {
const product_id = req.query.productId;
const quantity = req.query.quantity;
const user = req.user.id;
router.get('/get_cart', checkJwt, (req, res, next) => {
Cart.findOne({ user: req.user.id })
.populate({
path: 'user'
})
.populate({
path: 'item'
})
.exec((err, cart) => {
res.json({
msg: 'User not exists',
cart: cart
});
})
})
module.exports = router;
I am trying to populate the task_item but I am not able to do. If anyone knows please see this code.

Populate() Mongoose is not returning joined data

Well, I´am trying to retrieve Name and Lastname from user who created the document but it´s not working, it still returning Mongo´s Id
This is my areas model
var mongo = require('mongoose'),
validator = require('mongoose-unique-validator'),
Schema = mongo.Schema
var model = new Schema({
NAME: { type: String, required: true, unique: true, max: 50, min: 3 },
STATUS: { type: String, default: 'active' },
ADDED_BY: { type: Schema.Types.ObjectId, ref: 'users' },
ADDED_DATE: { type: Date, default: Date.now }
}, {collection :'areas'})
model.plugin( validator, { message: 'The {PATH} is not valid or duplicated' } )
module.exports = mongo.model('Area', model )
This is the user model
var mongo = require('mongoose'),
validator = require('mongoose-unique-validator'),
Schema = mongo.Schema
var userSchema = new Schema({
PERSONAL_DATA: {
NAME: { type: String, required: [ true, 'The name is necessary' ], max: 50 },
LAST_NAME: { type: String, required: [ true, 'the lastname is necessary' ], max: 100 },
PHOTO: { type: String, max: 100 },
BIRTHDAY: { type: Date },
MARITIAL_STATUS: { type: Schema.Types.ObjectId, ref: 'maritial_statuses' },
GENDER: { type: String, max: 1 },
EMAIL: { type: String, required: true },
},
COMPANY_DATA: {
JOB: { type: Schema.Types.ObjectId, ref: 'jobs' },
AREA: { type: Schema.Types.ObjectId, ref: 'areas' },
ROLE: { type: Schema.Types.ObjectId, ref: 'roles' },
BOSS: { type: Schema.Types.ObjectId, ref: 'users' },
}
}, { collection: 'users' } )
model.plugin( validator, { message: 'The {PATH} is not valid or duplicated' } )
module.exports = mongo.model('User', userSchema )
And this is my areas route
var express = require('express'),
model = require('../../models/catalogs/areas'),
app = express()
app.get('/:from', (req, res) => {
var from = parseInt( req.params.from )
model.find()
.sort('NAME').populate({ path: 'users', select: 'NAME LAST_NAME'})
.limit(10).skip(from)
.exec((error, data) => {
if (error) {
return res.status(500).json({
success: false,
error
})
}
res.status(200).json({
success: true,
data
})
})
})
module.exports = app
The response is
{
"success": true,
"data": [
{
"STATUS": "active",
"_id": "5c547f4adadf433914f72c8c",
"NAME": "Contabilidad y Finanzas",
"ADDED_BY": "5c4f562deec6f4defeea759b",
"ADDED_DATE": "2019-02-01T17:18:02.680Z",
"__v": 0
},
{
"STATUS": "active",
"_id": "5c547f3edadf433914f72c8b",
"NAME": "Tecnologías",
"ADDED_BY": "5c4f562deec6f4defeea759b",
"ADDED_DATE": "2019-02-01T17:17:50.579Z",
"__v": 0
}
]
}
As you seen, ADDED_BY is a field joined to Users and I want to retrieve that information. I don´t know what is wrong with my code.

Resources