How to populate the value from array of Objectid? - node.js

I'm Populating array of objects i don't know how i didn't get the result ?
Here my Schema for Todo model Each todo can have multiple collaborators
collaborators: [{
collaborator: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Users'
}
}]
the code doing the populate
const task = await Todo.find().populate('collaborators.collaborator').exec()
and i expected this query will give the todo info and all collobarotor info as well but only it give as a todo info only
Result i get
[
{
_id: 5eb672eb197e5d1afca21a23,
title: 'testing colla',
todo_description: 'paptefhfbjebjfbhjebfa.m',
priority: 'Low',
duedate: 2020-05-09T09:07:30.000Z,
image: [ [Object] ],
status: 'In Progress',
userid: 5e900762314fd13148cd3393,
assignee: 'nikil',
collaborators: [ [Object], [Object] ],
__v: 0
}
]

Related

Mongoose deep populate() returns empty array

I need a help on mongoose deep population. Basically, I have an ItemGroupSchema having a _id referenced to ItemSchema and items being an array of references to ItemSchema as well.
const ItemSchema = new mongoose.Schema<IItem>({
// information fields about item type, quantity, model, size,...
}); // its model is ItemModel
const ItemGroupSchema = new mongoose.Schema<IItemGroup>({
_id: { type: mongoose.Schema.Types.ObjectId, required: true, ref: ItemModel.modelName },
items: [{ type: mongoose.Schema.Types.ObjectId, ref: ItemModel.modelName }]
}, { _id: false }); // its model is ItemGroupModel
From a valid _id input, I do the following:
Get the items of it from ItemGroupModel; done.
With the items of _id I got, I populate it from ItemGroupSchema so I can have items of items of _id; done.
Now, I should have items of items inside items of _id. Next is to populate only on items of _id from ItemSchema to have some information to work on, which is not done yet.
The issue is that, populate() operation of the last step gives me an empty items array. Below is how each operation looks like step by step:
1.
ItemGroupModel.find({ _id: 'root' });
{
_id: 'root',
items: ['parent1', 'parent2']
}
2.
ItemGroupModel.find({ _id: 'root' }).populate({ path: 'items', model: ItemGroupModel.modelName });
{
_id: 'root',
items: [
{ _id: 'parent1', items: ['child1', 'child2'] },
{ _id: 'parent2', items: ['child3']
]
}
3.
ItemGroupModel.find({ _id: 'root' }).populate({ path: 'items', model: ItemGroupModel.modelName, populate: { path: '_id', model: ItemModel.modelName }});
{
_id: 'root',
items: [] // yes, empty
}
// I expect it to be
{
_id: 'root',
items: [
{ _id: { _id: 'parent1', type: 'gun', quantity: 1, size: 1 }, items: ['child1', 'child2'] },
{ _id: { _id: 'parent2', type: 'backpack', quantity: 1, size: 1 }, items: ['child3']
]
}
use this aggregation on ItemSchema collection
[{
from: 'ItemGroup',
localField: 'items',
foreignField: '_id',
as: 'items'
}]

Mongodb returning object inside array element

I have this mongoose schema,
const Schema = mongoose.Schema;
const productSchema = new Schema({
name: { type: String, required: true },
image: { type: String, required: true },
saleSizes: [ //Sizes that a particular item has, ex.. Size P , M, G XG
{
saleSize: { type: String, required: true }, //actual sizes, ex.. P
price: { type: Number, required: true }, // sales price for size P
},
],
category: { type: String, required: true },
active: { type: Boolean, default: true },
});
const Product = mongoose.model('Product', productSchema);
module.exports = Product;
when I load the page , I use the find() method to list all my itens with the sale sizes and prices.
this is the function that i'm using.
function homeController() {
return {
async index(req, res) {
const products = await Product.find();
console.log(products);
const categories = [
...new Set(products.map((product) => product.category)),
];
return res.render('home', { products: products, categories: categories });
},
};
}
the return for the find() method is this.
[
{
active: true,
_id: 60affa70d981bc59b64f2e09,
name: 'Alface Americana',
image: 'alface-americana.png',
saleSizes: [ [Object], [Object] ],
category: 'Hortaliças'
},
{
active: true,
_id: 60affa70d981bc59b64f2e0a,
name: 'Couve',
image: 'Couve.png',
saleSizes: [ [Object], [Object] ],
category: 'Hortaliças'
},
{
active: true,
_id: 60affa70d981bc59b64f2e0b,
name: 'Agrião',
image: 'agriao.png',
saleSizes: [ [Object], [Object] ],
category: 'Hortaliças'
},
{
active: true,
_id: 60affa70d981bc59b64f2e0c,
name: 'Rúcula',
image: 'rucula.png',
saleSizes: [ [Object], [Object] ],
category: 'Hortaliças'
},
{
active: true,
_id: 60affa70d981bc59b64f2e0d,
name: 'Limão Taiti',
image: 'limao-taiti.png',
saleSizes: [ [Object], [Object] ],
category: 'Frutas'
},
{
active: true,
_id: 60affa70d981bc59b64f2e0e,
name: 'Goiaba Vermelha',
image: 'goiaba-vermelha.png',
saleSizes: [ [Object], [Object] ],
category: 'Frutas'
}
....
]
Note that saleSizes Properties return as array of objects.
saleSizes: [ [Object], [Object] ].
I need the return to be something like this.
{
active: true,
_id: 60affa70d981bc59b64f2e18,
name: 'Granola',
image: 'granola.png',
price: '500',
saleSizes: [
{saleSize: "P", price: "100"},
{saleSize: "G", price: "200"}
],
category: 'Grãos'
}
what is the best approach to accomplish that?.
PS: sorry for my English, i'm from Brasil and still Learning (I think this is a forever process).
It is returned correctly. saleSizes is the array of Objects. {saleSize: "P", price: "100"} is Object. You can try to access those nested objects like this:
let size = saleSizes[0].saleSize;
let price = saleSizes[0].price;
After Nenad Milosavljevic comment, I change my html code to this.
<% product.saleSizes.forEach(function (saleSize){%>
<span class="font-bold text-lg">R$ <%= saleSize.price %></span>
<button
type="button"
class="size py-1 px-4 rounded-full uppercase text-xs"
><%= saleSize.saleSize %>
</button>
<% })%>
I'm using EJS by the way, now I have a button for each sale Size and a price as well.
Thank You so much for the Help, I was trying to solve a problem that isn't a problem.

how to populate array of objects in mongoose that reference to another schema

hello i went to populate all author with Course.
const courses = await Course.find().populate('author','name -_id');
console.log(courses);
const Author = mongoose.model('Author',mongoose.Schema({
name:{
type:String,
required:true
},
bio:String,
website:String
}));
const Course = mongoose.model('Course',mongoose.Schema({
name:String,
author:[{
type: mongoose.Schema.Types.ObjectId,
ref:'Author'
}]
}));
this is what i get:
[ { author: [ [Object], [Object] ],
_id: 5cdc596bfd5a1e33e4833b2b,
name: 'nodejs course',
__v: 1 } ]
but i went to populate author name inside the author array
like this [{author:[{name:'jhon'},{name:'jhon2'}],
[ { author: [ [Object], [Object] ],
_id: 5cdc596bfd5a1e33e4833b2b,
name: 'nodejs course',
__v: 1 } ]
I believe this should work for you:
const courses = await Course
.find({})
.populate('author')
.exec();
console.log(courses);

Check if sub document is found in $project

I am trying to find all the trips provided by a company, grouped by the driver of the bus, and check if a given passenger was part of the trip.
Content is an array that can have reference to multiple models: User, Cargo, etc.
I can somewhat achieve my desired result using:
traveled: { $in: [ passengerId, "$content.item" ] },
But i want to confirm that the matched id is indeed a 'User'(passenger). I have tried:
traveled: { $and: [
{ $in: [ passengerId, "$content.item" ] },
{ $in: [ `Passenger`, "$content.kind" ] },
]},
But it also matches if the passed id has a kind of 'Cargo' when there is another content with a kind of 'User' is inside the array.
// Trip
const schema = Schema({
company: { type: Schema.Types.ObjectId, ref: 'Company', required: false },
driver: { type: Schema.Types.ObjectId, ref: 'User', required: true },
description: { type: String, required: true },
....
content: [{
kind: { type: String, required: true },
item: { type: Schema.Types.ObjectId, refPath: 'content.kind', required: true }
}]
});
const Trip = mongoose.model('Trip', schema, 'trips');
Trip.aggregate([
{ $match: { company: companyId } },
{
$project: {
_id: 1,
driver: 1,
description: 1,
traveled: { $in: [ passengerId, "$content.item" ] },
// traveled: { $and: [
// { $in: [ passengerId, "$content.item" ] },
// { $in: [ `Passenger`, "$content.kind" ] },
// ]},
}
},
{
$group : {
_id: "$driver",
content: {
$push: {
_id: "$_id",
description: "$description",
traveled: "$traveled",
}
}
},
}
]).then(console.log).catch(console.log);
There is no $elemMatch operator in $project stage. So to use mimic similar functionality you can create $filter with $size being $gt > 0.
Something like
"traveled":{
"$gt":[
{"$size":{
"$filter":{
"input":"$content",
"as":"c",
"cond":{
"$and":[
{"$eq":["$$c.item",passengerId]},
{"$eq":["$$c.kind","User"]}
]
}
}
}},
0
]
}

$pull seems to just set an element to null

I'm trying to setup a delete button where a lesson can be deleted from a class. Using $pull seems to just set lesson_id to null though. Is there a way to remove that element completely?
var classSchema = new Schema({
title: { type: String, required: true },
lessons: [{
_id: false,
lesson_id: {type: mongoose.Schema.Types.ObjectId, ref: 'Lesson'}
}]
});
module.exports.deleteLesson = function(class_id, lesson_id, callback){
Class.update(
{'_id': class_id},
{ $pull: {lessons: {'lesson_id.$._id': lesson_id}}},
callback
)
}
For example
{ _id: 5808,
title: 'cd',
__v: 0,
lessons: [ { lesson_id: [Object] }, { lesson_id: [Object] } ] }
becomes
{ _id: 5808,
title: 'cd',
__v: 0,
lessons: [ { lesson_id: null }, { lesson_id: [Object] } ] }
If you need to delete an element from lessons (which is an array), then you need to just perform the deletion of element from the array and then perform a save operation. I have written code showcasing a similar approach.
Class.findOne({ _id: class_id }, function(err, cls) {
# Delete the element (for example, using underscore)
cls.lessons = _.without(cls.lessons, class_id);
cls.save(function (err) {
callback(err);
});
});

Resources