Mongoose won't populate an array or object - node.js

Im having an issue where i have a Fixtures schema like so:
const FixtureSchema = mongoose.Schema({
home: {
club: {
type: mongoose.Schema.Types.ObjectId,
ref: 'club'
},
score: {
type: Number,
default: 0
},
scorers: [
{
player: {
type: mongoose.Schema.Types.ObjectId,
ref: 'player'
}
}
]
},
away: {
club: {
type: mongoose.Schema.Types.ObjectId,
ref: 'club'
},
score: {
type: Number,
default: 0
},
scorers: [
{
player: {
type: mongoose.Schema.Types.ObjectId,
ref: 'player'
}
}
]
},
match_num: {
type: Number,
required: true
},
date: {
type: Date,
default: Date.now()
}
});
module.exports = Fixture = mongoose.model('fixture', FixtureSchema);
Club schema:
const ClubSchema = new mongoose.Schema({
name: {
type: String,
required: true
}
});
module.exports = Club = mongoose.model('club', ClubSchema);
Player Schema:
const PlayerSchema = new mongoose.Schema({
name: {
type: String,
require: true
},
club: {
type: mongoose.Schema.Types.ObjectId,
ref: 'club'
},
stats: {
starts: {
type: Number,
default: 0
},
goals: {
type: Number,
default: 0
},
assists: {
type: Number,
default: 0
},
goal_streak: {
type: Number,
default: 0
}
}
});
module.exports = Player = mongoose.model('player', PlayerSchema);
I make a request like this:
router.get('/', async (req, res) => {
try {
const fixture = await Fixture.find()
.populate('player', ['name'])
.populate('club', ['name']);
res.json(fixture);
} catch (err) {
console.error(err.message);
}
});
Postman get request gives me:
[
{
"home": {
"score": 1,
"club": "5e3dfcffb52ec61c30fc44cd",
"scorers": [
{
"_id": "5e4aac5d81d92b368398bd4d",
"player": "5e3dfddd4884f51cb7ee61e9"
}
]
},
"away": {
"score": 0,
"club": "5e3dfd18b52ec61c30fc44ce",
"scorers": []
},
"date": "2020-02-17T15:07:57.229Z",
"_id": "5e4aac5d81d92b368398bd4c",
"match_num": 1,
"__v": 0
}
]
Why is it not populating the name of the player or the club??? It works when it is not stored in an array or object.. Ive tried looking for advice on other topics but cant find anything relating to this..
Thanks for any replies and advice

Turns out it was the same as the other questions!!! lol..
If i change :
.populate('club', ['name']);
to
.populate('home.club', ['name']);
and so on
it solves it...

Related

MongoDB geting an empty array from an aggregation

So I created this controller to get me the sum of all the orders totalPrice made by months
const getMonthlyOrderTotal = async (req, res) => {
try {
const year = req.params.year;
const aggregatePipeline = [
{
$match: {
createdAt: {
$gte: new Date(`${year}-01-01T00:00:00.000`),
$lt: new Date(`${year}-12-31T23:59:59.999`)
}
}
},
{
$group: {
_id: {
$month: "$createdAt"
},
total: {
$sum: "$totalPrice"
}
}
},
{
$sort: {
_id: 1
}
}
];
const orderTotals = await Order.aggregate(aggregatePipeline);
res.json(orderTotals);
} catch (err) {
res.status(500).json({ message: err.message });
}
};
this is the orderModel I am using
import mongoose from "mongoose";
const orderSchema = mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "User",
},
client: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Client",
},
orderItems: [
{
name: { type: String, required: true },
qty: { type: Number, required: true },
image: { type: String },
price: { type: Number, required: true },
product: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Product",
},
},
],
totalPrice: {
type: Number,
required: true,
default: 0.0,
},
taxPrice: {
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,
},
},
{
timestamps: true,
}
);
const Order = mongoose.model("Order", orderSchema);
export default Order;
and when I try to test this API in postman "http://localhost:5001/orders/orderstotal/2022" I always get an empty array even though there is stored data in mongoDB orders Collection

One to many with MongoDB (Mongoose) with .populate()

What I am doing
I am trying to return a player by playerId with all ref items from each object in it's schema. In this example, I am specifically talking about the players inventory.
How can I return all reference items and their properties?
In my service file, I am getting my player with:
/**
* Get a player by playerId
* #param playerId
* #returns {Promise<*>}
*/
module.exports.getPlayer = async (playerId) => {
return await Player.findOne({ playerId: playerId }).populate('inventory');
};
And this is my returned JSON
{
"success": true,
"data": {
"_id": "63bb1f3ec17d33f4d2a87194",
"playerId": 4183489039,
"name": "AlanGreyjoy",
"currency": {
"copper": 500,
"silver": 10,
"gold": 0
},
"online": false,
"inventory": [
{
"currentDurability": 0,
"item": "63ba0c54407456969ba38615",
"amount": 1,
"_id": "63bc4fa070eaa247288e3573",
"createdAt": "2023-01-09T17:32:16.643Z",
"updatedAt": "2023-01-09T17:32:16.643Z"
}
],
"bank": [],
"questTracker": [],
"friends": [],
"knownRecipes": [],
"jobs": [],
"createdAt": "2023-01-08T19:53:34.903Z",
"updatedAt": "2023-01-09T17:32:16.643Z",
"__v": 1
}
}
As you can see, the item in the inventory array is not populating with the ref item from the items collection.
I have googled and googled and tried so many different things, but nothing is working.\
The item does exist in the db
My Models
My Player.model.js
const mongoose = require('mongoose');
const toJSON = require('../plugins/mongoToJson');
const Schema = mongoose.Schema;
const questTracker = new Schema(
{
quest: { type: mongoose.Schema.Types.ObjectId, ref: 'Quest' },
complete: { type: Boolean, default: false },
},
{ timestamps: true }
);
const friends = new Schema(
{
player: { type: mongoose.Schema.Types.ObjectId, ref: 'Player' },
isFavorite: { type: Boolean, default: false },
},
{ timestamps: true }
);
const knownRecipes = new Schema(
{
recipe: { type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' },
},
{ timestamps: true }
);
const jobs = new Schema(
{
job: { type: mongoose.Schema.Types.ObjectId, ref: 'Job' },
},
{ timestamps: true }
);
const inventoryItems = new Schema(
{
item: { type: mongoose.Schema.Types.ObjectId, ref: 'Item' },
amount: { type: Number, default: 0 },
currentDurability: { type: Number, default: 0 },
},
{ timestamps: true }
);
const bank = new Schema(
{
item: { type: mongoose.Schema.Types.ObjectId, ref: 'Item' },
amount: { type: Number, default: 0 },
},
{ timestamps: true }
);
const playerSchema = new Schema(
{
playerId: {
type: Number,
unique: true,
required: true,
},
name: {
type: String,
required: true,
unique: true,
},
currency: {
type: Object,
default: {
copper: 500,
silver: 10,
gold: 0,
},
},
inventory: [inventoryItems],
bank: [bank],
questTracker: [questTracker],
friends: [friends],
knownRecipes: [knownRecipes],
jobs: [jobs],
online: {
type: Boolean,
default: false,
},
},
{ timestamps: true }
);
const PlayerModel = mongoose.model('player', playerSchema);
module.exports = PlayerModel;
My Item.model.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const toJSON = require('../plugins/mongoToJson');
const vendorPriceSchema = mongoose.Schema({
copper: {
type: Number,
default: 0,
},
silver: {
type: Number,
default: 0,
},
gold: {
type: Number,
default: 0,
},
});
const itemSchema = new Schema(
{
title: {
type: String,
required: true,
unique: true,
},
assetId: {
type: Number,
required: true,
},
description: {
type: String,
},
equipDescription: {
type: String,
},
additionalDescription: {
type: String,
},
consumableUseDescription: {
type: String,
},
itemLevel: {
type: Number,
},
requiredLevel: {
type: Number,
},
type: {
type: String,
required: true,
},
subtype: {
type: String,
required: true,
},
stamina: {
type: Number,
},
intellect: {
type: Number,
},
criticalStrike: {
type: Number,
},
agility: {
type: Number,
},
mastery: {
type: Number,
},
maxDurability: {
type: Number,
},
vendorPrice: { vendorPriceSchema },
minDamage: {
type: Number,
default: 0,
},
maxDamage: {
type: Number,
default: 0,
},
speed: {
type: Number,
},
maxStack: {
type: Number,
},
},
{ timestamps: true }
);
const ItemModel = mongoose.model('Item', itemSchema);
module.exports = ItemModel;
You can use something like this:
module.exports.getPlayer = async (playerId) => {
return await Player.findOne({ playerId: playerId }).populate({
path: "inventory",
populate: {
path: "item",
},
});
};

Could not find path in schema while using arrayfilters in mongoose

This is my shema in mongoose
import {Schema, model} from 'mongoose'
const EmployeeSchema = new Schema({
employeeCode: {
type: String,
},
name: {
type: String,
},
appraisal: {
status: {
type: String,
enum: ["not started", "in progress", "completed", "not started", "self rating"],
default: "not started"
},
objective_group: [{
name: {
type: Schema.Types.ObjectId,
ref: "ObjectiveGroup",
required: true
},
value: {
type: Number,
},
objective_type: [{
name: {
type: Schema.Types.ObjectId,
ref: "ObjectiveType",
required: true
},
value: {
type: Number,
},
objective_description: [{
name: {
type: Schema.Types.ObjectId,
ref: "ObjectiveDescription",
required: true
},
value: {
type: Number,
},
ratings: {
type: {
type: Schema.Types.ObjectId,
ref: "Ratings",
}
},
}],
training_recommendation: {
type: Schema.Types.ObjectId,
ref: 'TrainingRecommendation'
},
other_recommendation: {
type: Schema.Types.ObjectId,
ref: 'OtherRecommendation'
},
}],
}],
},
})
export default model('Employee', EmployeeSchema)
Here is my code for the following task
const updateValue = asyncHandler(async (req: Request, res: Response) => {
const {id, rating} = req.body
const employee = await Employee.findOneAndUpdate({
"_id": "6204935ebca89023952f2da9",
"appraisal.objective_group._id": "6207ec6a8bfc1226d3f36fb1"
},
{
$set: {
"appraisal.$[objective_group].value": 1234
}
},
{
arrayFilters: [
{
'objective_group._id': new mongoose.Types.ObjectId("6207ec6a8bfc1226d3f36fb1")
}
]
}
)
res.status(StatusCodes.OK).json({
employee
});
})
Here I am trying to update the value field in objective_group. To achieve this I am using arrayfilter. But I am getting this Error
Error: Could not find path "appraisal.0._id" in schema
When I am mongoose v6 it's showing this error. on mongoose v5 I am not getting any errors but the operation is not succeeding
There is the possibility that I am not using arrayfilters in the right way because inside objective_group I am storing objects inside the array.
I am new to StackOverflow so sorry for some mistakes
You just have a slight error with the path you're providing, the error means that the path you gave resolved into a none array value.
You just need to change your update part from:
"appraisal.$[objective_group].value": 1234
To:
"appraisal.objective_group.$[objective_group].value": 1234
Like so:
db.collection.update({
"_id": "6204935ebca89023952f2da9",
"appraisal.objective_group._id": ObjectId("6207ec6a8bfc1226d3f36fb1")
},
{
$set: {
"appraisal.objective_group.$[group].value": 1234
}
},
{
arrayFilters: [
{
"group._id": ObjectId("6207ec6a8bfc1226d3f36fb1")
}
]
})
Mongo Playground

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.

Node.js with mongoose delete one array element

I am trying to delete one array element when I click delete button on jade view page.
When clicked, it's going to send selected instructor objected as req.body.
At sever side, it will find courses that contain the instructor objectId.
Any idea for me?
Thank you for reading it.
here is my code:
var id = req.body._id;
clist.find({ instructors: { $in: [id] } }).exec(function (err, result) {
result.forEach(function (obj) {
clist.update(
{ _id: new mongoose.Types.ObjectId(obj._id)},
{ $pull: { instructors : [new mongoose.Types.ObjectId(id)] } }
);
console.log(new mongoose.Types.ObjectId(obj._id) + ' was deleted');
});
});
Schema Clist and ilist:
var instructorlist = mongoose.Schema({
name: { type: String, required: true },
age: { type: Number, required: true },
gender: { type: String, required: true },
DOB: { type: Date, required: true, default: Date.now },
email: { type: String, required: true },
phone: { type: Number, required: true },
address: { type: String, required: true },
dateofstart: { type: Date, required: true},
courses: [{
type: mongoose.Schema.Types.ObjectId,
ref: "clist"
}]
});
var courselist = mongoose.Schema({
coursename: { type: String, required: true },
coursenumber: { type: String, required: true },
coursecredit: { type: Number, required: true },
courseroom: { type: String, required: false },
courseregisteddate: {type: Date, default: Date.now},
students: [{
type: mongoose.Schema.Types.ObjectId,
ref: "slist"
}],
instructors: [{
type: mongoose.Schema.Types.ObjectId,
ref: "ilist"
}]
});
one example for mongodb :
{
"_id": {
"$oid": "591a7a3b391a1842e8a69e23"
},
"coursename": "JDKD",
"coursenumber": "COMP4483",
"coursecredit": 4,
"courseroom": "sdaf",
"instructors": [
{
"$oid": "591a374422a3a13d38c0bbe5"
}
],
"students": [],
"courseregisteddate": {
"$date": "2017-05-16T04:04:11.848Z"
},
"__v": 0
}
When I add instructor objectID in Course.
var newcourse = new clist({
'coursename': req.body.coursename, 'coursenumber': req.body.coursenumber, 'coursecredit': req.body.coursecredit
, 'courseroom': req.body.room, 'instructors': instructors._id
});
Use same operation to find and update multiple
clist.update(
{ instructors: { $in: [id] }},
{ $pull: { instructors : { _id : new mongoose.Types.ObjectId(id) } } }, //or{ $pull: { instructors: mongoose.Types.ObjectId(id) } }
{
multi:true
},
function(error, success){
if(error){
console.log("error",error)
}
console.log("success",success)
});

Resources